挺神仙的置换题
SP422 TRANSP2 - Transposing is Even More Fun
这个博客除了开始举例子别的都是对的:
https://blog.csdn.net/BraketBN/article/details/50668414
首先理解题意:
就是单纯的矩阵转置,一行一行存储。
(全部下标从0开始)
一个位置(i,j)在转置后会变成(j,i)
原来存储的位置是(下标从0开始):i*2^b+j
现在是:j*2^a+i
发现其实就是一个二进制数循环右移b位得到的
向要到的位置连边,会形成K个置换环
每个置换环内部换会len-1省一次
总共就是:2^(a+b)-K
关键是求K
问题转化为:
有2^(a+b)个元素
两个元素是等价类当且仅当A循环右移b位和B相等
求等价类的个数
分母枚举所有的置换
分子计算所有不动点的个数
画画图,发现,在(a+b)的环上,一次走b步,最后有gcd(a,b)个置换环,和一次走gcd(a,b)步是一样的
所以,可以这样写,然后反演:
摘自:https://blog.csdn.net/BraketBN/article/details/50668414
然后,2的次幂可以预处理,phi线性筛,d可以快速质因数分解,然后dfs枚举约数
n直接求逆元,复杂度就是O(因子个数*T)
代码:
#include<bits/stdc++.h> #define reg register int #define il inline #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int mod=1000003; const int N=1e6+4; int vis[N],pri[N],phi[N],tot; int mindiv[N]; int yin[1004],zhi[1004],cnt; void sieve(){ phi[1]=1; for(reg i=2;i<=1e6;++i){ if(!vis[i]){ vis[i]=1; mindiv[i]=i; pri[++tot]=i; phi[i]=i-1; } for(reg j=1;j<=tot;++j){ if(pri[j]*i>1e6) break; vis[pri[j]*i]=1; mindiv[i*pri[j]]=pri[j]; if(i%pri[j]==0){ phi[i*pri[j]]=phi[i]*pri[j]; break; }else{ phi[i*pri[j]]=phi[i]*phi[pri[j]]; } } } } ll ans; int pw[N]; int g,n; void dfs(int x,int fac){ if(x==cnt+1){ ans=(ans+(ll)pw[fac*g]*phi[n/fac]%mod)%mod; return; } dfs(x+1,fac); int tmp=yin[x]; for(reg i=1;i<=zhi[x];++i){ dfs(x+1,fac*tmp); tmp=tmp*yin[x]; } } int gcd(int a,int b){ return b?gcd(b,a%b):a; } int qm(int x,int y){ int ret=1; while(y){ if(y&1) ret=(ll)ret*x%mod; x=(ll)x*x%mod; y>>=1; } return ret; } int main(){ int t,a,b; sieve(); pw[0]=1; for(reg i=1;i<=1e6;++i) pw[i]=(ll)pw[i-1]*2%mod; rd(t); while(t--){ rd(a);rd(b); if(a==0||b==0){ puts("0");continue; } g=gcd(a,b); n=(a+b)/gcd(a,b); // cout<<" n "<<n<<endl; cnt=0; ans=0; int tmp=n; while(mindiv[tmp]){ yin[++cnt]=mindiv[tmp]; zhi[cnt]=0; while(mindiv[tmp]==yin[cnt]) tmp/=mindiv[tmp],++zhi[cnt]; } dfs(1,1); ans=(ll)ans*qm(n,mod-2)%mod; ans=(qm(2,a+b)-ans+mod)%mod; printf("%lld ",ans); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/2/18 11:31:26 */
总结:
一个置换思想套置换本身的好题
反演还过来凑凑热闹