题意:
有一个环由n个组合和一个中心珠子组成,现在有k中颜色,问相邻的不能同色的染色方案数。
题解:
这题的n很大所以只能枚举约数gcd(n,i)=r,但是k也超级大,完全无法用关系矩阵解决。那么要考虑是否有规律。对于中心有珠子的这种染色法,明显可以枚举中心珠子的颜色,然后计算k-个颜色嫩染多少种的情况,最后乘以k即可。我们可以枚举外围的第一个珠子颜色,然后用dp解决这种排列问题。现在假设枚举第一个珠子颜色是黑色,那么开始的状态dp[1][0]=0,dp[1][1]=1,接下来这个两个方程很快就能出来:dp[i][1]=dp[i][1],dp[i][0]=dp[i][0]*(k-3)+dp[i][1]*(k-2);最终要得到dp[r][0].发现这个r非常的大,无法直接递推,考虑用举证优化这个dp,于是就用矩阵乘法搞定,ORZ!
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> #include<stack> #include<string> #define B(x) (1<<(x)) using namespace std; typedef long long ll; void cmax(int &a,int b){ if(b>a)a=b; } void cmin(int &a,int b){ if(b<a)a=b; } void cmax(ll &a,ll b){ if(b>a)a=b; } void cmin(ll &a,ll b){ if(b<a)a=b; } void add(int &a,int b,int mod){ a=(a+b)%mod; } void add(ll &a,ll b,ll mod){ a=(a+b)%mod; } void add(int &a,int b){ a+=b; } void add(ll &a,ll b){ a+=b; } const int oo=0x3f3f3f3f; const ll MOD=1000000007; const int maxn = 15; int fac[1000000],cnt; int prime[100000],p; struct MAZE{ ll maze[4][4]; int n; MAZE(){ n=0;} MAZE(int n_){ memset(maze,0,sizeof maze); n=n_; } MAZE operator*(const MAZE &a)const{ MAZE b(n); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) b.maze[i][j]=(b.maze[i][j]+maze[i][k]*a.maze[k][j]%MOD+MOD)%MOD; return b; } }; MAZE maze_pow(MAZE a,int k){ MAZE b(a.n); for(int i=1;i<=b.n;i++)b.maze[i][i]=1; while(k){ if(k&1) b=a*b; a=a*a; k>>=1; } return b; } void get_fac(int n){ cnt=0; for(int i=1;(ll)i*i<=n;i++){ if(n%i==0){ fac[cnt++]=i; if(n/i!=i) fac[cnt++]=n/i; } } //sort(fac,fac+cnt); } ll dfs(int s,int x){ ll res=0; for(int i=s;i<p;i++){ res+=x/prime[i]-dfs(i+1,x/prime[i]); } return res; } ll Count(int n){ p=0; int m=n; for(int i=2;(ll)i*i<=n;i++){ if(n%i==0){ prime[p++]=i; while(n%i==0) n/=i; } } if(n>1&&prime[p-1]!=n)prime[p++]=n; return ((ll)m-dfs(0,m))%MOD; } ll ex_gcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1; y=0; return a; } ll d=ex_gcd(b,a%b,x,y); ll t=x; x=y; y=t-a/b*y; return d; } ll solve(int c,int r){ MAZE a(2); a.maze[1][1]=c-3;a.maze[1][2]=c-2; a.maze[2][1]=1;a.maze[2][2]=0; a=maze_pow(a,r-1); ll ans=a.maze[1][2]*(c-1)%MOD; return ans; } int main(){ int n,c; while(scanf("%d %d",&n,&c)!=EOF){ get_fac(n); ll ans=0; for(int i=0;i<cnt;i++){ ans=(ans+Count(n/fac[i])*solve(c,fac[i])%MOD)%MOD; } ans=(ans%MOD+MOD)%MOD; ans=(ans*c)%MOD; ll x=0,y=0; ex_gcd(n,MOD,x,y); x=(x%MOD+MOD)%MOD; ans=(ans*x)%MOD; cout<<ans<<endl; } return 0; }