【纪中集训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;
    }
    

猜你喜欢

转载自www.cnblogs.com/Paul-Guderian/p/10640299.html
今日推荐