HAOI2018 [HAOI2018] Dyeing [number of combinations + tolerance + NTT]

topic

In order to repay Little C's apple, Little G intends to give Little C, who loves art, a canvas. This canvas can be abstracted into a sequence of length \(N\) , and each position can be dyed \(M\) one of the colors.

However, small C only cares about the number of colors that appear exactly \(S\) in the \(N\) positions of the sequence. If there are \(K\) colors that appear \(S\) times , then Small C will produce \(W_k\) pleasantness.

Little C wants to know what the sum of the pleasures he can obtain modulo 1004535809 for all possible staining schemes.

input format

Read data from standard input. Three integers \(N, M, S\) on the first line .

The next line is \(M + 1\) integers, and the \(i\)th number represents \(W_{i-1}\)
​ .

output format

Output to standard output. Output an integer representing the answer.

input sample

8 8 3
3999 8477 9694 8454 3308 8961 3018 2255 4910

Sample output

524070430

hint

Special properties: \(\forall 1 \le i \le m, W_i = 0\)
For the data of \(100\%\) , satisfy \(0 \le W_i < 10045358090\)

answer

Let \(E = min(\lfloor \frac{N}{S} \rfloor,M)\)
We enumerate several colors with \(K\) times, then the rest cannot have \(K\) Second, using tolerance and exclusion we can get the formula:
\[ans = \sum\limits_{i = 0}^{E} w[i]{M \choose i} {N \choose iS} \frac{(iS )!}{(S!)^{i}} \sum\limits_{j = 0}^{E - i} (-1)^{j} {M - i \choose j} {N - iS \choose jS} \frac{(jS)!}{(S!)^{j}} (M - i - j)^{N - iS - jS}\]
that \((M - i - j)^{N - iS - jS}\) is very difficult to handle, we consider converting it:
\[ans = \sum\limits_{i = 0}^{E} w[i]{M \choose i} {N \choose iS} \frac{(iS)!}{(S!)^{i}} \sum\limits_{j = i}^{E} (-1)^{j - i} {M - i \choose j - i } {N - iS \choose jS - iS} \frac{(jS - iS)!}{(S!)^{j - i}} (M - j)^{N - jS}\]
Then expand the number of combinations , the numerator and denominator are canceled, and the remainder is as follows:
\[ans = \sum\limits_{i = 0}^{E} w[i]\frac{M!N!}{i!} \sum\limits_{j = i}^{E} \frac{( -1)^{j - i}(M - j)^{N -jS}}{(j - i)!(M - j)!(N - jS)!(S!)^{j}}\ ]
Let's exchange the position of \(i,j\) , after finishing:
\[ans = \sum\limits_{j = 0}^{E} \frac{M!N!(Mj)^{N - jS }}{(M - j)!(N - jS)!(S!)^{j}} \sum\limits_{i = 0}^{j} \frac{w[i]}{i!} * \frac{(-1)^{j - i}}{(j - i)!}\]
The left side is the expression only related to \(j\) , the right side is \(f(x) = \frac{ The convolution NTT of w[x]}{x!}\) and \(g(x) = \frac{(-1)^{x}}{x!}\) can

The original root of \(10045358090\) is \(3\)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 100005,maxm = 10000005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
const int G = 3,P = 1004535809;
int qpow(int a,int b){
    int ans = 1;
    for (; b; b >>= 1,a = 1ll * a * a % P)
        if (b & 1) ans = 1ll * ans * a % P;
    return ans;
}
int fac[maxm],fv[maxm],inv[maxm];
int L,R[maxn << 2],f[maxn << 2],g[maxn << 2],n,m;
int N,M,S,W[maxn];
void NTT(int* a,int F){
    for (int i = 0; i < n; i++) if (i < R[i]) swap(a[i],a[R[i]]);
    for (int i = 1; i < n; i <<= 1){
        int gn = qpow(G,(P - 1) / (i << 1));
        for (int j = 0; j < n; j += (i << 1)){
            LL g = 1,x,y;
            for (int k = 0; k < i; k++,g = 1ll * g * gn % P){
                x = a[j + k]; y = 1ll * g * a[j + k + i] % P;
                a[j + k] = (x + y) % P; a[j + k + i] = (x - y + P) % P;
            }
        }
    }
    if (F == 1) return;
    int nv = qpow(n,P - 2); reverse(a + 1,a + n);
    for (int i = 0; i < n; i++) a[i] = 1ll * a[i] * nv % P;
}
void init(){
    int E = max(N,M);
    fac[0] = 1;
    for (int i = 1; i <= E; i++) fac[i] = 1ll * fac[i - 1] * i % P;
    inv[0] = inv[1] = 1;
    for (int i = 2; i <= E; i++) inv[i] = 1ll * (P - P / i) * inv[P % i] % P;
    fv[0] = 1;
    for (int i = 1; i <= E; i++) fv[i] = 1ll * fv[i - 1] * inv[i] % P;
}
void solve(){
    int t,E = min(M,N / S);
    for (int i = 0; i <= E; i++){
        t = (i & 1) ? -1 : 1;
        f[i] = 1ll * W[i] * fv[i] % P;
        g[i] = 1ll * t * fv[i] % P;
    }
    L = 0; m = E + E;
    for (n = 1; n <= m; n <<= 1) L++;
    for (int i = 1; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    NTT(f,1); NTT(g,1);
    for (int i = 0; i < n; i++) f[i] = 1ll * f[i] * g[i] % P;
    NTT(f,-1);
    int ans = 0,tmp;
    for (int i = 0; i <= E; i++){
        tmp = 1ll * fac[M] * fac[N] % P * qpow(M - i,N - i * S) % P;
        tmp = 1ll * tmp * fv[N - i * S] % P * fv[M - i] % P * qpow(fv[S],i) % P;
        ans = (ans + 1ll * tmp * f[i] % P) % P;
    }
    printf("%d\n",(ans % P + P) % P);
}
int main(){
    N = read(); M = read(); S = read();
    for (int i = 0; i <= M; i++) W[i] = read();
    init();
    solve();
    return 0;
}

Guess you like

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