SPOJ419Transposing is Fun Pólya定理+欧拉函数

Posted CQzhangyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ419Transposing is Fun Pólya定理+欧拉函数相关的知识,希望对你有一定的参考价值。

【SPOJ419】Transposing is Fun

题意:给你一个$2^a\times2^b$的矩阵,将$1...n$中的数依次从左到右,从上往下填到矩阵里,再把矩阵转置,然后把所有数从左到右,从上往下拿出来得到一个新的排列$A$。你现在每次可以交换两个数,问你从$1...n$变成排列$A$最少要进行多少次操作。
询问次数$\le400000,a+b\le 10^6$
题解:首先我们可以找到所有的循环节,如果一个循环节中有$x$个数,需要交换$x-1$次。所以我们只需要求出循环节的个数$k$,那么答案就是$2^{a+b}-k$。
如何求出循环节的个数呢?假设$a=5,b=3$,考虑元素$(12,1)$,其二进制表示为$(01010,001)$,它原来的位置是$01010?001$,新位置是$001?01010$。相当于将每个数的位置二进制向右移动$b$位。
所以,我们可以令$gcd(a,b)=g$,将$g$个数分成一组,相当于用$2^g$种颜色去染$a+b\over g$个珠子,就又变成了上面那题。
依旧要用欧拉函数优化,同POJ2154。

#include <cstring>
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll P=1000003;
const int N=2000000;
int T,a,b,n,m,g,num;
ll ans;
ll pw[N+10];
int cnt[100],p[100];
int phi[N+10],np[N+10],pri[N],xp[N+10],mn[N+10];
inline ll pm(ll x,int y)
{
    ll z=1;
    while(y)
    {
        if(y&1) z=z*x%P;
        x=x*x%P,y>>=1;
    }
    return z;
}
int gcd(int a,int b)
{
    return (!b)?a:gcd(b,a%b);
}
void dfs(int x,int d)
{
    if(x==m+1)
    {
        ans=(ans+pw[g*d]*phi[n/d])%P;
        return ;
    }
    for(int i=0;i<=cnt[x];i++,d*=p[x])  dfs(x+1,d);
}
inline void init()
{
    phi[1]=1;
    int i,j,p;
    for(pw[0]=i=1;i<=N;i++) pw[i]=(pw[i-1]<<1)%P;
    for(i=2;i<=N;i++)
    {
        if(!np[i])  pri[++num]=i,mn[i]=i,xp[i]=1,phi[i]=i-1;
        for(j=1;j<=num&&i*pri[j]<=N;j++)
        {
            p=pri[j],np[i*p]=1,mn[i*p]=p;
            if(i%p==0)
            {
                phi[i*p]=phi[i]*p,xp[i*p]=xp[i]+1;
                break;
            }
            phi[i*p]=phi[i]*(p-1),xp[i*p]=1;
        }
    }
}
inline void work()
{
    scanf("%d%d",&a,&b),ans=m=0;
    if(!a||!b)
    {
        puts("0");
        return ;
    }
    g=gcd(a,b),n=(a+b)/g;
    int t=n;
    while(t!=1)
    {
        p[++m]=mn[t],cnt[m]=xp[t];
        while(mn[t]==p[m])  t/=p[m];
    }
    dfs(1,1);
    printf("%lld\n",(pw[a+b]-ans*pm(n,P-2)%P+P)%P);
}
int main()
{
    init();
    scanf("%d",&T);
    while(T--)  work();
    return 0;
}//1 2 30000

以上是关于SPOJ419Transposing is Fun Pólya定理+欧拉函数的主要内容,如果未能解决你的问题,请参考以下文章

C. Nastya Is Transposing Matrices

修复中间有换行的句子:Python is \n is fun

[CodeForces 372A] Counting Kangaroos is Fun

Codeforces 372B Counting Rectangles is Fun

[PTA]实验1-3 Programming in C is fun!

题解 CF372A Counting Kangaroos is Fun