多校2021记录

题目:
I love playing games
I love counting
I love sequence

I love playing games

如果双方到终点最短路长度不同或能到终点的情况不同,则可以直接判出胜利方。若最短路长度相同,则先手不会败,而且还会尝试使后手失败;后手不会胜,会尝试得到平局。
f i , j f_{i,j} fi,j 为先手在 i i i,后手在 j j j 的结局。可以通过 i , j i,j i,j 距离终点的最短路判断出当前该谁移动。
时空复杂度 O ( n 2 ) O(n^2) O(n2)

#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;
#define R register int
#define I inline void
#define N 1001
vector<int>G[N];
int dis[N],f[N][N];
I BFS(int S,int&n){
	for(R i=1;i<=n;i++){
		dis[i]=N;
	}
	dis[S]=0;
	queue<int>Q;
	Q.push(S);
	while(Q.empty()==false){
		int x=Q.front();
		Q.pop();
		for(vector<int>::iterator T=G[x].begin();T!=G[x].end();T++){
			if(dis[*T]==N){
				dis[*T]=dis[x]+1;
				Q.push(*T);
			}
		}
	}
}
I DP(int x,int y){
	if(f[x][y]==-1){
		if(dis[x]==dis[y]){
			f[x][y]=0;
			for(vector<int>::iterator T=G[x].begin();T!=G[x].end();T++){
				if(dis[*T]==dis[x]-1){
					DP(*T,y);
					f[x][y]|=f[*T][y];
				}
			}
		}else{
			f[x][y]=1;
			for(vector<int>::iterator T=G[y].begin();T!=G[y].end();T++){
				if(dis[*T]==dis[y]-1){
					DP(x,*T);
					f[x][y]&=f[x][*T];
				}
			}
		}
	}
}
I Solve(){
	int n,m,x,y,z,a,b;
	scanf("%d%d%d%d%d",&n,&m,&x,&y,&z);
	for(R i=1;i<=n;i++){
		G[i].clear();
	}
	for(R i=0;i!=m;i++){
		scanf("%d%d",&a,&b);
		G[a].push_back(b);
		G[b].push_back(a);
	}
	BFS(z,n);
	if(dis[x]<dis[y]){
		puts("1");
	}else if(dis[y]<dis[x]){
		puts("3");
	}else if(dis[x]==N){
		puts("2");
	}else{
		for(R i=1;i<=n;i++){
			for(R j=1;j<=n;j++){
				f[i][j]=-1;
			}
			f[i][i]=1;
		}
		f[z][z]=0;
		f[x][y]=-1;
		DP(x,y);
		if(f[x][y]==1){
			puts("1");
		}else{
			puts("2");
		}
	}
}
int main(){
	int t;
	scanf("%d",&t);
	for(R i=0;i!=t;i++){
		Solve();
	}
	return 0;
}
I love counting

要求的数显然可以用Trie数上的节点表示出来。离线询问,在每个Trie节点上嵌入一个HH的项链的线段树即可维护。
时空复杂度 O ( n log ⁡ 2 2 n ) O(n \log_2^2n) O(nlog22n)

#include<stdio.h>
#include<vector>
using namespace std;
#define R register int
#define I inline
#define N 100001
char BF[1000000],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=BF)+fread(BF,1,1000000,stdin),p1==p2)?0:*p1++)
I void Read(int&x){
    char t=GC;
    x=0;
    while(t<48||t>57){
        t=GC;
    }
    while(t>47&&t<58){
        x=x*10+(t^48);
        t=GC;
    }
}
struct Query{
	int Lf,ValA,ValB,Id;
};
I Query Pair(int l,int x,int y,int d){
	Query res;
	res.Lf=l;
	res.ValA=x;
	res.ValB=y;
	res.Id=d;
	return res;
}
vector<Query>Q[N];
int a[N],ans[N],Root[262144],Last[N],ct;
struct SegmentNode{
	int Ls,Rs,Sum;
}s[40000000];
I void GetNode(int&x){
	ct++;
	x=ct;
}
I void Init(){
	for(R i=2;i!=262144;i++){
		Root[i]=i-1;
	}
	ct=262142;
}
I void Add(int p,int lf,int rt,const int x,const int d){
	s[p].Sum+=d;
	if(lf!=rt){
		int mid=lf+rt>>1;
		if(x>mid){
			if(s[p].Rs==0){
				GetNode(s[p].Rs);
			}
			Add(s[p].Rs,mid+1,rt,x,d);
		}else{
			if(s[p].Ls==0){
				GetNode(s[p].Ls);
			}
			Add(s[p].Ls,lf,mid,x,d);
		}
	}
}
I void Insert(int x,const int c,int&n){
	int p=1;
	for(R i=16;i!=-1;i--){
		p=p<<1|x>>i&1;
		if(Last[x]!=0){
			Add(Root[p],1,n,Last[x],-1);
		}
		Add(Root[p],1,n,c,1);
	}
}
I int GetSum(int p,int lf,int rt,const int l,const int r){
	if(l<=lf&&rt<=r){
		return s[p].Sum;
	}
	int mid=lf+rt>>1,res=0;
	if(l<=mid&&s[p].Ls!=0){
		res=GetSum(s[p].Ls,lf,mid,l,r);
	}
	if(r>mid&&s[p].Rs!=0){
		res+=GetSum(s[p].Rs,mid+1,rt,l,r);
	}
	return res;
}
I int GetAns(int l,int r,int a,int b,int&n){
	int res=0,p=1;
	for(R i=16;i!=-1;i--){
		if((b>>i&1)==1){
			res+=GetSum(Root[p<<1|a>>i&1],1,n,l,r);
		}
		p=p<<1|(a^b)>>i&1;
	}
	return res+GetSum(Root[p],1,n,l,r);
}
int main(){
	int n,m,l,r,x,y;
	Read(n);
	for(R i=1;i<=n;i++){
		Read(a[i]);
	}
	Read(m);
	for(R i=0;i!=m;i++){
		Read(l);
		Read(r);
		Read(x);
		Read(y);
		Q[r].push_back(Pair(l,x,y,i));
	}
	Init();
	for(R i=1;i<=n;i++){
		Insert(a[i],i,n);
		Last[a[i]]=i;
		for(vector<Query>::iterator T=Q[i].begin();T!=Q[i].end();T++){
			ans[T->Id]=GetAns(T->Lf,i,T->ValA,T->ValB,n);
		}
	}
	for(R i=0;i!=m;i++){
		printf("%d\n",ans[i]);
	}
	return 0;
}
I love sequence

根据题面得出需要快速进行序列的神奇卷积。由于卷积和三进制相关,考虑FWT。原版FWT为 F W T ( A ) = { F W T ( A 0 ) + F W T ( A 1 ) , F W T ( A 0 ) − F W T ( A 1 ) } FWT(A)=\{FWT(A_0)+FWT(A_1),FWT(A_0)-FWT(A_1)\} FWT(A)={FWT(A0)+FWT(A1),FWT(A0)FWT(A1)}
这里修改FWT的变换方式:
F W T ( A ) = { F W T ( A 0 ) , F W T ( A 0 ) + F W T ( A 1 ) + F W T ( A 2 ) , F W T ( A 0 ) + F W T ( A 2 ) } FWT(A)=\{FWT(A_0),FWT(A_0)+FWT(A_1)+FWT(A_2),FWT(A_0)+FWT(A_2)\} FWT(A)={FWT(A0),FWT(A0)+FWT(A1)+FWT(A2),FWT(A0)+FWT(A2)}
长度为 n n n 的数列卷积的时间复杂度为 O ( n log ⁡ 3 n ) O(n \log_3n) O(nlog3n)
时间复杂度 O ( n log ⁡ 3 n ln ⁡ n ) O(n \log_3n \ln n) O(nlog3nlnn),空间复杂度 O ( n ) O(n) O(n)

#include<stdio.h>
#define R register int
#define L long long
#define I inline
#define N 200001
#define P 1000000007
I int Add(int x,const int y){
	x+=y;
	return x<P?x:x-P;
}
int a[N],b[N],c[N],db[531441],d[531441];
I void FWT(int*A,const int len){
	for(R i=1;i!=len;i*=3){
		for(R j=0;j!=len;j+=i*3){
			for(R k=j;k!=i+j;k++){
				A[(i<<1)+k]=Add(A[(i<<1)+k],A[k]);
				A[i+k]=Add(A[i+k],A[(i<<1)+k]);
			}
		}
	}
}
I void IFWT(int*A,const int len){
	for(R i=1;i!=len;i*=3){
		for(R j=0;j!=len;j+=i*3){
			for(R k=j;k!=i+j;k++){
				A[i+k]=Add(A[i+k],P-A[(i<<1)+k]);
				A[(i<<1)+k]=Add(A[(i<<1)+k],P-A[k]);
			}
		}
	}
}
I void Calc(int n,int len){
	for(R i=0;i!=len;i++){
		d[i]=db[i]=0;
	}
	for(R i=1;i<=n;i++){
		d[i]=a[i];
		db[i]=b[i];
	}
	FWT(d,len);
	FWT(db,len);
	for(R i=0;i!=len;i++){
		d[i]=(L)d[i]*db[i]%P;
	}
	IFWT(d,len);
}
int main(){
	int n,ans=0,m,len=1,s;
	scanf("%d",&n);
	for(R i=1;i<=n;i++){
		scanf("%d",a+i);
	}
	for(R i=1;i<=n;i++){
		scanf("%d",b+i);
	}
	for(R i=1;i<=n;i++){
		scanf("%d",c+i);
	}
	for(R p=n;p!=0;p--){
		m=n/p;
		while(len<=m){
			len*=3;
		}
		Calc(m,len);
		s=1;
		for(R k=1;k!=len;k++){
			s=(L)s*c[p]%P;
			ans=((L)s*d[k]+ans)%P;
		}
	}
	printf("%d",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值