【纪中集训2019.3.25】礼物

题目

描述

​ 一个\(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\)

  • \[\begin{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;
    }
    
    
posted @ 2019-04-02 07:28  大米饼  阅读(297)  评论(0编辑  收藏  举报