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
    
  • 相关阅读:
    Android中Context具体解释 ---- 你所不知道的Context
    JDK6、Oracle11g、Weblogic10 For Linux64Bit安装部署说明
    matplotlib 可视化 —— 定制 matplotlib
    matplotlib 可视化 —— 移动坐标轴(中心位置)
    matplotlib 可视化 —— 移动坐标轴(中心位置)
    matplotlib 可视化 —— 定制画布风格 Customizing plots with style sheets(plt.style)
    matplotlib 可视化 —— 定制画布风格 Customizing plots with style sheets(plt.style)
    指数函数的研究
    指数函数的研究
    指数分布的研究
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8227370.html
Copyright © 2011-2022 走看看