UVA12298 Super Poker II 题解

Description

Luogu传送门

Solution

其实就是个 NTT 多项式乘法板子。

我不会告诉你我一开始还推了半天生成函数(然后发现直接把 5e4 的系数全都直接赋值就完了QwQ

那么本题的解法就是这样=-=

开 4 个数组,表示 4 种花色的多项式。对于每一组数据,暴力把每一位的系数都赋上:

合数位系数都为 1,质数位都为 0,再把被删掉牌的位系数改为 0。

注意:不知道为什么在本题中 1 被看成了质数,系数为 0。

然后把 4 个数组都卷起来就完了。

然后就没啦。

还有一个小问题,一般的模数会被卡,我是直接用的 kls 的模数,得用 __int128

Code

#include <bits/stdc++.h>
#define Int __int128

using namespace std;

namespace IO{
    inline Int read(char &ch){
        Int x = 0;
        ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x;
    }

    template <typename T> inline void write(T x){
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace IO;

const Int N = 1e6 + 10;
const Int P = 5e4;
const Int mod = 4179340454199820289ll;
const Int G = 3, Gi = 1393113484733273430ll;
Int n, m, k;
Int a[N], b[N], c[N], d[N], e[N], rev[N];
Int p[N], tot;
bool vis[N];
char ch;

namespace NTT{
    Int lim, len;

    inline Int qpow(Int a, Int b){
        Int res = 1;
        while(b){
            if(b & 1) res = res * a % mod;
            a = a * a % mod, b >>= 1;
        }
        return res;
    }

    inline void get_rev(Int n){
        lim = 1, len = 0;
        while(lim <= n) lim <<= 1, ++len;
        for(int i = 0; i <= lim; ++i) p[i] = (p[i >> 1] >> 1) | ((i & 1) << (len - 1));
    }

    inline void ntt(Int A[], Int lim, Int type){
        for(int i = 0; i < lim; ++i)
            if(i < p[i]) swap(A[i], A[p[i]]);
        for(int mid = 1; mid < lim; mid <<= 1){
            Int Wn = qpow(type == 1 ? G : Gi, (mod - 1) / (mid << 1));
            for(int i = 0; i < lim; i += (mid << 1)){
                Int w = 1;
                for(int j = 0; j < mid; ++j, w = w * Wn % mod){
                    Int x = A[i + j], y = w * A[i + j + mid] % mod;
                    A[i + j] = (x + y) % mod;
                    A[i + j + mid] = (x - y + mod) % mod;
                }
            }
        }
        if(type == 1) return;
        Int inv = qpow(lim, mod - 2);
        for(int i = 0; i < lim; ++i) A[i] = A[i] * inv % mod;
    }

    inline void Mul(Int n, Int m, Int a[], Int b[]){
        get_rev(n + m);
        ntt(a, lim, 1), ntt(b, lim, 1);
        for(int i = 0; i <= lim; ++i) a[i] = a[i] * b[i] % mod;
        ntt(a, lim, -1);
    }
}
using namespace NTT;

inline void euler(){
    for(int i = 2; i <= P; ++i){
        if(!vis[i]) p[++tot] = i;
        for(int j = 1; j <= tot && i * p[j] <= P; ++j){
            vis[i * p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
}

inline void del(){
    int x = read(ch);
    if(ch == 'S') a[x] = 0;
    if(ch == 'H') b[x] = 0;
    if(ch == 'C') c[x] = 0;
    if(ch == 'D') d[x] = 0;
}

signed main(){
    euler();
    while(1){
        n = read(ch), m = read(ch), k = read(ch);
        if(!n && !m && !k) break;
        memset(a, 0, sizeof(a)), memset(b, 0, sizeof(b));
        memset(c, 0, sizeof(c)), memset(d, 0, sizeof(d));
        for(int i = 0; i <= m; ++i)
            a[i] = b[i] = c[i] = d[i] = vis[i];
        for(int i = 1; i <= k; ++i) del();
        Mul(m, m, a, b), Mul(m, m, c, d), Mul(m << 1, m << 1, a, c);
        for(int i = n; i <= m; ++i) write(a[i]), puts("");
        puts("");
    }
    return 0;
}

\[\_EOF\_ \]

原文地址:https://www.cnblogs.com/xixike/p/15634836.html