2018.10.05 练习赛

[T1 序列计数]

题解:

\(DP\)可做,\(F[i][j]\),表示第\(i\)个数组成的好序列左边差\(j\)个数时的方案数;

\(code\):

#include<stdio.h>
#include<algorithm>
#include<ctype.h>
#define mod 998244353
using namespace std;

inline int add(int a,int b){return a+b<mod?a+b:a+b-mod;}

int n,a[5005],f[5005][5005];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	if(a[1]>0&&a[1]<=n-1) f[1][a[1]]=1;
	for(int i=2;i<=n;i++)
	{
		for(int j=0;j<=n;j++)
		{
			f[i][j]=f[i-1][j];
			if(j) f[i][j-1]=add(f[i][j-1],f[i-1][j]); 
		}
		if(a[i]>0&&a[i]<=n-1) f[i][a[i]]=add(f[i][a[i]],f[i-1][0]+1);	
	}
	printf("%d",f[n][0]);
}
 

[T2 僵尸大战植物引发的惨♂案 ]

题解:

预处理出对于一个点\(S\),起点到他的距离,他一路坐到站底时的最优时间(坐到站底\(T\)的时间\(+\)坐到终点的时间),把这个当成边丢进\(vector\),二分一个答案验证;

\(code:\)

#include<stdio.h>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const ll N=25001,inf=1e18;
struct www{
	ll to,len;
	www(ll to=0,ll len=0):
		to(to),len(len){}
	bool operator<(const www x)const{
		return len>x.len;
	}
};
priority_queue<www>q;
vector<www>g[N],qwq[N];
ll n,m,s,t,lim,w[N],sum[N],sub[N],dis[N];
void dijkstra(ll s,bool f){
	for(ll i=0;i<n;i++)dis[i]=inf;
	q.push(www(s,0));dis[s]=0;
	while(!q.empty()){
		ll x=q.top().to,_dis=q.top().len;
		q.pop();if(dis[x]!=_dis)continue;
		for(ll i=g[x].size()-1;i>=0;i--){
			ll y=g[x][i].to,len=g[x][i].len+_dis;
			bool ok=f|(len+qwq[x][i].len<=lim);
			if(dis[y]>len&&ok)dis[y]=len,q.push(www(y,len)); 
		}
	}
}
int main(){
	scanf("%lld%lld%lld%lld",&n,&m,&s,&t);
	for(ll i=1;i<=m;i++){
		scanf("%lld",&sub[0]);
		for(ll j=1;j<=sub[0];j++)scanf("%lld",&sub[j]);
		for(ll j=1;j<sub[0];j++){
			scanf("%lld",&w[j]);
			sum[j]=sum[j-1]+w[j]; 
		}
		for(ll j=1;j<sub[0];j++){
			g[sub[j]].push_back(www(sub[j+1],w[j]));
			g[sub[j+1]].push_back(www(sub[j],w[j]));
			qwq[sub[j]].push_back(www(sub[sub[0]],sum[sub[0]-1]-sum[j]));
			qwq[sub[j+1]].push_back(www(sub[1],sum[j-1]));
		}
	}
	dijkstra(t,1);
	for(ll i=0;i<n;i++)
	for(ll j=qwq[i].size()-1;j>=0;j--)
	qwq[i][j].len+=dis[qwq[i][j].to];
	ll l=0,r=inf;
	while(l<=r){
		lim=l+r>>1;
		dijkstra(s,0);
		if(dis[t]==inf)l=lim+1;
		else r=lim-1;
	}
	printf("%lld",l);
}

[T3 深夜放毒]

题解:

说实话想到很简单,写起来确实恶心,典型的树套树,横向维护一颗线段树,纵向维护一颗线段树,不想写=_=,于是放上出题人自己的代码

\(code:\)

#include <stdio.h>
#include <iostream>
#include <algorithm>
#define ll long long 
using namespace std;
int k,lim;
const int QAQ=20000000;
int ls[QAQ],rs[QAQ];
ll sum[QAQ],lazy[QAQ];
int tot=1;
void mdf(int now,int l,int r,int x,int y,ll v)
{
	if(x<=l&&y>=r)
	{
		sum[now]+=(r-l+1)*v;
		lazy[now]+=v;
		return;
	}
	int mid=l+r >>1;
	if(lazy[now])
	{
		ll v=lazy[now];
		lazy[now]=0;
		if(!ls[now])ls[now]=++tot;
		if(!rs[now])rs[now]=++tot;
		sum[ls[now]]+=(mid-l+1)*v;
		sum[rs[now]]+=(r-mid)*v;
		lazy[ls[now]]+=v;
		lazy[rs[now]]+=v;
	}
	if(x<=mid)
	{
		if(!ls[now])ls[now]=++tot;
		mdf(ls[now],l,mid,x,y,v);
	}
	if(y>mid)
	{
		if(!rs[now])rs[now]=++tot;
		mdf(rs[now],mid+1,r,x,y,v);
	}
	sum[now]=sum[ls[now]]+sum[rs[now]];
}
ll get(int now,int l,int r,int x,int y)
{
	if(!now)return 0;
	if(x<=l&&y>=r)return sum[now];
	int mid=l+r >>1;
	ll tmp=0;
	if(lazy[now])
	{
		ll v=lazy[now];
		lazy[now]=0;
		if(!ls[now])ls[now]=++tot;
		if(!rs[now])rs[now]=++tot;
		sum[ls[now]]+=(mid-l+1)*v;
		sum[rs[now]]+=(r-mid)*v;
		lazy[ls[now]]+=v;
		lazy[rs[now]]+=v;
	}
	if(x<=mid)tmp+=get(ls[now],l,mid,x,y);
	if(y>mid)tmp+=get(rs[now],mid+1,r,x,y);
	return tmp;
}
int lb(int x)
{return x&(-x);}
void MODIFY(int xxx,int x,int y,ll v)
{while(xxx<=k)mdf(xxx,0,lim-1,x,y,v),xxx+=lb(xxx);}
ll QUERY(int xxxx,int x)
{ll t=0;while(xxxx)t+=get(xxxx,0,lim-1,x,x),xxxx-=lb(xxxx);return t;}
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline int R()
{
	int p=0;
	char o=GC;
	while(o<48||o>57)o=GC;
	while(o>=48&&o<=57)
	{
		p=(p<<1)+(p<<3)+o-48;
		o=GC;
	}
	return p;
}
void FangDu()
{
	int x=R(),h=R();
	ll v=R();
	mdf(k+1,0,lim-1,x/k-h,x/k,v);
	mdf(k+1,0,lim-1,(x+1)/k,(x+1)/k+h,-v);
	MODIFY(x%k+1,x/k-h,x/k,v);
	MODIFY((x+1)%k+1,(x+1)/k,(x+1)/k+h,-v);
}
void XunWen()
{
	int x=R();
	int alk=(x+1)/k-1;
	ll ans=0;
	if(alk>=0)
		ans+=get(k+1,0,lim-1,0,alk);
	if((x+1)%k!=0)
		ans+=QUERY(x%k+1,x/k);
	printf("%lld\n",ans);
}
//Please Do Not Diss Me !!!!
int main()
{
	k=R(),lim=R();
	int i,m=R();
	tot=k+1;
	while(m--)
	{
		i=R();
		if(i==1)FangDu();
		else XunWen();
	}
	return 0;
}
posted @ 2018-10-05 20:51  Katoumegumi  阅读(97)  评论(0编辑  收藏  举报
返回顶部