zoukankan      html  css  js  c++  java
  • 【SPOJ419】Transposing is Fun Pólya定理+欧拉函数

    【SPOJ419】Transposing is Fun

    题意:给你一个$2a imes2b$的矩阵,将$1...n$中的数依次从左到右,从上往下填到矩阵里,再把矩阵转置,然后把所有数从左到右,从上往下拿出来得到一个新的排列$A$。你现在每次可以交换两个数,问你从$1...n$变成排列$A$最少要进行多少次操作。
    询问次数$le400000,a+ble 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+bover 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
    ",(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
    
  • 相关阅读:
    Mybatis源代码分析之类型转换
    eclipse中对于@override注解的函数报父类没有该方法
    Mybatis源代码分析之metadata包
    Android GC
    有道单词本导出xml转换.
    广播的接收与U盘广播
    Bitmap和Drawable相互转换方法
    如何提交程序到Android Market
    error parsing xml:unbound prefix
    android获取屏幕尺寸、密度
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8227370.html
Copyright © 2011-2022 走看看