SP422 TRANSP2

挺神仙的置换题

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
*/

总结:
一个置换思想套置换本身的好题

反演还过来凑凑热闹

原文地址:https://www.cnblogs.com/Miracevin/p/10396141.html