zoukankan      html  css  js  c++  java
  • [BZOJ3202][SDOI2013]项链

    bzoj
    luogu

    sol

    数论多合一。
    可以考虑分两步做。
    1、求有多少种不同的珠子,设其数量为(m)
    2、用(m)种颜色对(n)个珠子的项链染色,要求相邻不同色,且旋转相同视作同一种方案,求方案数。

    求有多少种不同的珠子

    (A=sum_{i=1}^asum_{j=1}^asum_{k=1}^a[gcd(i,j,k)=1])
    然而算重了。
    如果(i,j,k)都不相等的话就多算了(6)次,如果有两个相等就多算了(3)次,如果三个都相等......那肯定是三个(1)啦,并没有多算。
    这个问题怎么解决呢?我们再算(B=sum_{i=1}^asum_{j=1}^a[gcd(i,j)=1]),那么答案就是(frac 16(A+3B+2))(把每种情况补齐到(6)次,再一起除以(6))。
    (A)(B)是很简单的莫比乌斯反演,具体来说就是:

    [A=sum_{i=1}^alfloorfrac ai floor^3mu(i)\B=sum_{i=1}^alfloorfrac ai floor^2mu(i) ]

    求染色方案

    这里要用到(Burnside)定理。
    这里的置换只有一种,就是旋转。设旋转(i)个位置,那么就会有产生(gcd(i,n))个等价类。
    所以答案就是$$frac{sum_{i=1}^nf_{gcd(i,n)}}{n}$$其中(f_i)表示(i)个点的环染色的方案数。也可以认为是给一个长为(n)的序列染色,然后保证首尾不同色的方案数。
    考虑对上式做一些简化。因为(gcd(i,n))一定是(n)的约数,所以可以枚举某个约数(d),然后答案就变成了$$frac{sum_{d|n}f_dsum_{i=1}^n[gcd(i,n)=d]}{n}=frac{sum_{d|n}f_dvarphi(frac nd)}{n}$$

    (f_n)

    考虑一下(f_n)的递推。

    [f_n=(m-2)f_{n-1}+(m-1)f_{n-2},f_1=0,f_2=m(m-1) ]

    讲道理的话,前一种转移表示在末尾填一个与首尾都不相同的颜色,这样有(m-2)种选择;后一种转移表示先填一个和首位相同的颜色,再填一个不同色,这样有(1 imes(m-1))种选择。
    然后就可以矩乘了。

    (f_n)的通项公式

    有人跟我讲这题要求通项公式我就没去写矩乘。常数优秀一点说不定跑得过?
    下面讲一下求通项公式

    [f_n-(m-2)f_{n-1}-(m-1)f_{n-2}=0 ]

    其特征方程$$x^2-(m-2)x-(m-1)=0$$
    解得其特征根$$x_1=-1,x_2=m-1$$
    于是设其通项公式为$$f_i=a(-1)^i+b(m-1)^i$$
    (f_1=0,f_2=m(m-1))代入解得$$a=1-m,b=1$$
    所以$$f_i=(1-m)(-1)^i+(m-1)^i$$
    复杂度还是(O(log n))但是常数小很多。

    (varphi(n))

    最好不要枚举因数然后暴力算(varphi(n))
    一种可行的方案是:先将(n)质因数分解,然后(dfs)搜出每一个因数,在搜的过程中自然可以求出它的(varphi)
    这样的话总的复杂度就是(O(a+T(sqrt a+d(n)log n)))

    你以为这样就做完了吗

    (nle10^{14})
    这样可能会产生一个问题:(n)(P=10^9+7)的倍数。这样算出来的分子要除以(n),不好意思不存在逆元。
    怎么办呢?
    我们把答案对(P^2)取模。如果(P|n),那么分子既然是(n)的倍数就也是(P)的倍数。直接除以(P),接着还需要除以(frac nP),而(frac nP)在模(P)意义下是存在逆元的((nle P^2)),于是就可以乘逆元了。

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    const ll mod = 1000000007ll;
    const ll MOD = 1000000007ll*1000000007ll;
    const ll Inv6 = 833333345000000041ll;
    const int N = 10000005;
    int T,zhi[N],pri[N/10],tot,mu[N],cnt,q[30];ll n,m,p[30],ans;
    void add(ll &x,ll y){x+=y;if(x>=MOD)x-=MOD;}
    ll mul(ll x,ll y){
    	return (x*y-(ll)(((long double)x*y+0.5)/(long double)MOD)*MOD+MOD)%MOD;
    }
    ll sqr(ll x){return mul(x,x);}
    ll cub(ll x){return mul(mul(x,x),x);}
    ll fastpow(ll a,ll b){
    	ll res=1;
    	while (b) {if (b&1) res=mul(res,a);a=mul(a,a);b>>=1;}
    	return res;
    }
    ll fpow(ll a,ll b){
    	ll res=1;
    	while (b) {if (b&1) res=res*a%mod;a=a*a%mod;b>>=1;}
    	return res;
    }
    void init(){
    	mu[1]=1;
    	for (int i=2;i<N;++i){
    		if (!zhi[i]) pri[++tot]=i,mu[i]=-1;
    		for (int j=1;i*pri[j]<N;++j){
    			zhi[i*pri[j]]=1;
    			if (i%pri[j]) mu[i*pri[j]]=-mu[i];
    			else break;
    		}
    	}
    	for (int i=1;i<N;++i) mu[i]+=mu[i-1];
    }
    ll cal(ll n){
    	ll A=0,B=0;
    	for (ll i=1,j;i<=n;i=j+1){
    		j=n/(n/i);
    		add(A,mul(cub(n/i),mu[j]-mu[i-1]+MOD)%MOD);
    		add(B,mul(sqr(n/i),mu[j]-mu[i-1]+MOD)%MOD);
    	}
    	add(A,mul(B,3));add(A,2);return mul(A,Inv6);
    }
    ll F(ll n){
    	ll res=n&1?1-m:m-1;add(res,MOD);
    	add(res,fastpow(m-1+MOD,n));return res;
    }
    void dfs(int i,ll cur,ll phi){
    	if (i==cnt+1) {add(ans,mul(phi,F(n/cur)));return;}
    	dfs(i+1,cur,phi);
    	cur*=p[i];phi*=p[i]-1;dfs(i+1,cur,phi);
    	for (int j=2;j<=q[i];++j)
    		cur*=p[i],phi*=p[i],dfs(i+1,cur,phi);
    }
    int main(){
    	init();
    	scanf("%d",&T);while (T--){
    		scanf("%lld%lld",&n,&m);m=cal(m);
    		ll x=n;cnt=0;
    		for (int i=1;i<=tot&&(ll)pri[i]*pri[i]<=x;++i)
    			if (x%pri[i]==0){
    				p[++cnt]=pri[i];q[cnt]=0;
    				while (x%pri[i]==0) x/=pri[i],++q[cnt];
    			}
    		if (x>1) p[++cnt]=x,q[cnt]=1;
    		ans=0;dfs(1,1,1);
    		if (n%mod==0){
    			ans/=mod;
    			ans=ans*fpow(n/mod,mod-2)%mod;
    		}else{
    			ans%=mod;
    			ans=ans*fpow(n%mod,mod-2)%mod;
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    遍历文件夹及子文件夹_函数
    wbadmin与vssadmin
    WSB备份到远程共享文件夹的限制
    Linux 性能工具集
    shell 与 空格
    Git 仓库结构 (二)***
    Linux下scp的用法***
    FINDSTR 命令使用详解
    Git 的origin和master分析 ***
    Git push *****
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9657640.html
Copyright © 2011-2022 走看看