解题:SPOJ 422 Transposing is Even More Fun

题面

这种换来换去的东西很容易想到置换群那一套,然后题目甚至还暗示了二进制=。=

直接换的话显然是$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\n",(pw[a+b]-Query((a+b)/g,pw[g])+mod)%mod);
87         }
88     }
89     return 0;
90 }
View Code

 

posted @ 2019-02-25 21:28  Speranza_Leaf  阅读(286)  评论(0)    收藏  举报