题目
描述
一个(n)个珠子的手环,你可以选择其中(m)个将其染成金色;
但是连续的金色段的长度不能超过一个阈(yu,四声)值;
求:在旋转置换下的本质不同的方案数;
答案对(998244353)取模;
范围
$1 le T le 5 , 1 le n le 10^6 , 0 le k le m le n $ ;
题解
-
和这个题类型差不多:
https://www.cnblogs.com/Paul-Guderian/p/10590523.html -
同样有两种推法:
-
设(f(n,m))为不计旋转置换下的方案;
-
首先套用(polya)
-
[egin{align} ans &= frac{1}{n}sum_{d=1}^{n} f(gcd(d,n),frac{m}{frac{n}{gcd(d,n)}})[frac{n}{gcd(d,n)}|m]\ &= frac{1}{n}sum_{d|(n,m)}f(frac{n}{d},frac{m}{d})phi(d) end{align} ]
-
给出两种推(f(n,m))的方法;
[考虑在先搞好剩下的n-m个无色珠子,然后将m个金珠子插进去,注意分两边和中间插\ 容易得到答案对m的生成函数:F(x) = (sum_{i=0}^{k}x^i)^{n-m-1}(sum_{i=0}^{k}(i+1)x^i)\ 令G(x)=sum_{i=0}^{k}(i+1)x^i\ xG(x) = sum_{i=1}^{k+1}ix^i = G(x) - sum_{i=0}^{k}x^i + x^{k+1}(k+1) \ G(x) = frac{1-x^{k+1}(k+1)+x^{k+2}(k+1)}{(1-x)^2}\ 那么:\ F(x) = frac{(1-x^{k+1})^{n-m-1}}{(1-x)^{n-m+1}}[1-x^{k+1}(k+2)+x^{k+2}(k-1)]\ 用二项式定理和广义二项式定理(或者直接说泰勒展开)展开左边;\ 直接求的复杂度是frac{sigma(m)}{k+1}的\sigma(m)接近n loglog n ;\ 所以复杂度接近线性; ] -
另外一种是直接从组合的意义去计算(f(n,m));
[直接考虑去染金m个连续不超过k的珠子比较麻烦;\ 考虑成将n-m个珠子染黑,然后相邻两个珠子之间的距离不超过k\ 下文的m均指原定义中的n-m\ 考虑限定第一个珠子是黑色的,最后的放案需要乘以frac{n}{m}\ 相当于选取m个整数变量,满足:\ 1. 0 le a_0,a_1,...a_{m-1}le k\ 2. a_0+a_1+cdots+a_{m-1} = n-m\ 容斥1,插隔板统计2,可得最后的答案\ frac{n}{m}sum_{i=1}^{k}(-1)^i(^m_i)(^{n-1-(k+1)i}_{m-1});\ 类似复杂度分析\ ]#include<bits/stdc++.h> #define ll long long #define mod 998244353 using namespace std; const int N=1000010; int n,m,k,iv[N],fac[N],inv[N],vis[N],pr[N],phi[N],pt; int pw(int x,int y){ int re=1; while(y){ if(y&1)re=(ll)re*x%mod; y>>=1;x=(ll)x*x%mod; } return re; } void pre(){ iv[1]=1;for(int i=2;i<=1000000;++i)iv[i]=(ll)(mod-mod/i)*iv[mod%i]%mod; for(int i=fac[0]=inv[0]=1;i<=1000000;++i){ fac[i]=(ll)fac[i-1]*i%mod; inv[i]=(ll)inv[i-1]*iv[i]%mod; } phi[1]=1; for(int i=2;i<=1000000;++i){ if(!vis[i])phi[pr[++pt]=i]=i-1; for(int j=1,t;j<=pt&&i*pr[j]<=1000000;++j){ vis[t=i*pr[j]]=1; if(i%pr[j]==0){phi[t]=phi[i]*pr[j];break;} else phi[t]=phi[i]*(pr[j]-1); } } } int C(int x,int y){return x<y?0:(ll)fac[x]*inv[y]%mod*inv[x-y]%mod;} int cal(int n,int m){ if(n<=m)return 0; m=n-m; int re=0; for(int i=0;i<=m&&i*k<n;++i){ int now=(ll)C(m,i)*C(n-1-i*k,m-1)%mod; if(i&1)re=(re-now+mod)%mod; else re=(re+now)%mod; } return (ll)re*n%mod*iv[m]%mod; } int main(){ freopen("gift.in","r",stdin); freopen("gift.out","w",stdout); pre(); int T;scanf("%d",&T); while(T--){ scanf("%d%d%d",&n,&m,&k);k++; if(!m){puts("1");continue;} int ans=0; for(int i=1;i<=n&&i<=m;++i)if(n%i==0&&m%i==0){ ans=(ans+(ll)cal(n/i,m/i)*phi[i]%mod)%mod; } ans=(ll)iv[n]*ans%mod; cout<<ans<<endl; } return 0; }