这种换来换去的东西很容易想到置换群那一套,然后题目甚至还暗示了二进制=。=
直接换的话显然是$2^{a+b}$次,但是一个循环节里可以少换一次,然后问题就变成了数循环节
在一个循环节里的位置有什么特征?用二进制表示位置,那么他们的位置可以通过循环左移a位/循环右移b位互相表示,然后问题就变成了:在左移a位/右移b位的置换群作用下,在a+b个01构成的环里找等价类。仍然不好做,因为现在直接Burnside做不出来,Polya又还没法做,继续转换
我们把每$gcd(a,b)$个数缩成一个,也就是转成$frac{(a+b)}{gcd(a,b)}$个环数等价类。这样的好处是旋转都变成了1位,然后套上Polya就可以了,大概需要卡一卡常?
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=1e6+60,mod=1e6+3; 6 int T,a,b,cnt,c1,c2,pwe[10],prf[10]; 7 int pw[N],npr[N],pri[N],mind[N],fac[N],fai[N]; 8 int GCD(int a,int b) 9 { 10 return b?GCD(b,a%b):a; 11 } 12 void Add(int &x,int y) 13 { 14 x+=y; 15 if(x>=mod) x-=mod; 16 } 17 int Qpow(int x,int k) 18 { 19 if(k==1) return x; 20 int tmp=Qpow(x,k/2); 21 return k%2?1ll*tmp*tmp%mod*x%mod:1ll*tmp*tmp%mod; 22 } 23 void Pre() 24 { 25 npr[1]=true,mind[1]=1; 26 for(int i=2;i<=1000000;i++) 27 { 28 if(!npr[i]) pri[++cnt]=i,mind[i]=i; 29 for(int j=1,k;j<=cnt&&(k=i*pri[j])<=1000000;j++) 30 { 31 npr[k]=true,mind[k]=pri[j]; 32 if(i%pri[j]==0) break; 33 } 34 } 35 pw[0]=1; 36 for(int i=1;i<=1000000;i++) 37 pw[i]=pw[i-1]*2%mod; 38 } 39 void DFS(int idx,int num,int phi) 40 { 41 if(idx>c2) 42 fac[++c1]=num,fai[num]=phi; 43 else 44 { 45 int pr=prf[idx]; 46 DFS(idx+1,num,phi); 47 DFS(idx+1,num*=pr,phi*=pr-1); 48 for(int i=2;i<=pwe[idx];i++) 49 DFS(idx+1,num*=pr,phi*=pr); 50 } 51 } 52 void Decompose(int x) 53 { 54 if(x==1) 55 fac[c1=1]=1; 56 else 57 { 58 c2=0; 59 while(x!=1) 60 { 61 prf[++c2]=mind[x],pwe[c2]=0; 62 while(x%prf[c2]==0) x/=prf[c2],pwe[c2]++; 63 } 64 c1=0,DFS(1,1,1); 65 } 66 } 67 int Query(int len,int col) 68 { 69 int ret=0; 70 Decompose(len); 71 for(int i=1;i<=c1;i++) 72 Add(ret,1ll*fai[len/fac[i]]*Qpow(col,fac[i])%mod); 73 return 1ll*ret*Qpow(len,mod-2)%mod; 74 } 75 int main() 76 { 77 Pre(); 78 scanf("%d",&T); 79 while(T--) 80 { 81 scanf("%d%d",&a,&b); 82 if(!a||!b) puts("0"); 83 else 84 { 85 int g=GCD(a,b); 86 printf("%d ",(pw[a+b]-Query((a+b)/g,pw[g])+mod)%mod); 87 } 88 } 89 return 0; 90 }