Counting

Description

  
​ Math teacher is gone, English teacher is coming to class
  ​ His personality is different, and because everyone is a student of science class
  ​ He hopes that everyone can understand the joy of English in the process of number
letters​ He arranges them with m letters Combining,
​ get all the different strings of length n
​ (not all letters need to appear in the string)
  ​ For each string s
​ Define C(s) as the most frequent letter in s The number of occurrences
​ Then the question comes
​ All these character sets of size m, length n strings How many are
C(s)=k?
  

Input

  
​ A line of three integers n, m, k, representing length, character set and required C(s) respectively
  

Output

  
​ Output a line to represent
the result​ The answer is modulo 998244353
  

Sample Input

  
​   3 2 2
  

Sample Output

  
​   6
  

HINT

  
​ Data guarantee k≤n
​ For 10% of the data, 1≤n,m≤8
​ For 30% of the data, 1≤n,m≤200
​ For 50% of the data, 1≤n,m≤1000
​ For 100% data, 1≤n,m≤50000
  
​ Example explanation:
  
​ Suppose the two letters in the example are a, b
​ Then there are six aab, aba, abb, baa, bab, bba that meet the conditions
    
  
  

Solution

  
​ First, the most intuitive DP equations are listed.
  
  Note that \(f[i][j][k]\) is currently considering the \(i\) th letter, the \(j\) position in the string has been used, and the number of occurrences of the most letters does not exceed \ (k\) the number of options. The answer is \(f[m][n][k]-f[m][n][k-1]\) .
   
​ The transition equation is obviously to enumerate how many times the current letter is used:
\[ f[i][j][k]=\sum_{x=0}^k {j\choose x}f[i-1][jx] [k] \]
  ​ Then you can find that \(k\) is very redundant and does not participate in the transfer. That is to say , \(k\) only acts on the loop range control.
  
​ We try to omit the last dimension: \(f[i][j]\) . \(k\) still works, that is, the current \(f[i][j]\) corresponds to the original \(f[i][j][k]\) .
  
  ​ Now look at the equation:
\[ \begin{aligned} f[i][j]&=\sum_{x=0}^k{j\choose x}f[i-1][jx]\\ &=\sum_{x=0 }^k\frac{j!}{x!(jx)!}f[i-1][jx]\\ \frac{f[i][j]}{j!}&=\sum_{x= 0}^k\;x!\;\frac{f[i-1][jx]}{(jx)!} \end{aligned} \]
​ is obviously a form of convolution, and the left side of the equal sign The form is the same as that of the right half of the convolution . So each \(f[i]\) can be regarded as a polynomial
  
\[ f[i]=\frac{f[i][0]}{0!}+\frac{f[i][1] }{1!}x+\frac{f[i][2]}{2!}x^2+...+\frac{f[i][n]}{n!}x^n \
  
] The transition is this polynomial sum
  
\[ T(x)=\frac1{0!}+\frac1{1!}x+\frac1{2!}x^2...+\frac1{k!}x^k \]
  
  ​ 's convolution. That is, \(f[n]=f[0]*T^{n}(x)\)
  
​ and \(T(x)\) is independent and not affected by other things, so \(T(x )\) Convolve it with a fast power, and then convolve it with \(f[0]\) . According to the definition, \(f[0]=1\) , so it is equivalent to directly find \(T(x)\ )\(n\) power. Don't forget to multiply the answer by the factorial of \(n\) .
  

#include <cstdio>
#include <cstring>
using namespace std;
const int N=50005,MOD=998244353,G=3,B17=131100;
int fact[N],iact[N];
inline void swap(int &x,int &y){x^=y^=x^=y;}
inline int pow(int x,int y){
    int res=1;
    for(;y;x=1LL*x*x%MOD,y>>=1)
        if(y&1) res=1LL*res*x%MOD;
    return res;
}
namespace NTT{/*{{{*/
    int n,invn,bit,rev[B17],W[B17][2];
    void build(){
        int b=pow(G,MOD-2);
        for(int i=0;i<=17;i++){
            W[1<<i][0]=pow(G,(MOD-1)/(1<<i));
            W[1<<i][1]=pow(b,(MOD-1)/(1<<i));
        }
    }
    void init(int _n){
        for(n=1,bit=0;n<_n;n<<=1,bit++);
        invn=pow(n,MOD-2);
        for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
    }
    void clear(int *a){for(int i=0;i<n;i++)a[i]=0;}
    void ntt(int *a,int f){
        for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
        int u,v,w_n,w;
        for(int i=2;i<=n;i<<=1){
            w_n=W[i][f==-1];
            for(int j=0;j<n;j+=i){
                w=1;
                for(int k=0;k<i/2;k++){
                    u=a[j+k]; v=1LL*w*a[j+i/2+k]%MOD;
                    a[j+k]=(u+v)%MOD; a[j+i/2+k]=(u-v)%MOD;
                    w=1LL*w*w_n%MOD;
                }
            }
        }
        if(f==-1)
            for(int i=0;i<n;i++) a[i]=1LL*a[i]*invn%MOD;
    }
}/*}}}*/
void ksm(int *x,int y,int n,int *res){
    NTT::init((n+1)*2);
    NTT::clear(res);
    res[0]=1;
    for(;y;y>>=1){
        NTT::ntt(x,1);
        if(y&1){
            NTT::ntt(res,1);
            for(int i=0;i<NTT::n;i++) res[i]=1LL*res[i]*x[i]%MOD;
            NTT::ntt(res,-1);
            for(int i=n+1;i<NTT::n;i++) res[i]=0;
        }
        for(int i=0;i<NTT::n;i++) x[i]=1LL*x[i]*x[i]%MOD;
        NTT::ntt(x,-1);
        for(int i=n+1;i<NTT::n;i++) x[i]=0;
    }
}
int solve(int n,int m,int k){
    static int a[B17],b[B17];
    memset(a,0,sizeof a);
    for(int i=0;i<=k;i++) a[i]=iact[i];
    ksm(a,m,n,b);
    return 1LL*fact[n]*b[n]%MOD;
}
int main(){
    freopen("input.in","r",stdin);
    NTT::build();
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    fact[0]=1;
    for(int i=1;i<=n;i++) fact[i]=1LL*fact[i-1]*i%MOD;
    iact[n]=pow(fact[n],MOD-2);
    for(int i=n-1;i>=0;i--) iact[i]=1LL*iact[i+1]*(i+1)%MOD;
    int ans=(solve(n,m,k)-solve(n,m,k-1))%MOD;
    printf("%d\n",ans<0?ans+MOD:ans);
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324632788&siteId=291194637