题目:
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;
}