UVA - 12298 Super Poker II (FFT+母函数)

题意:有四种花色的牌,每种花色的牌中只能使用数值的约数个数大于2的牌.现在遗失了c张牌.每种花色选一张,求值在区间[a,b]的每个数值的选择方法有多少.
分析:约数个数大于2,即合数.所以先预处理出50000内的所有素数.
然后根据给出的c个遗失牌和素数与否.构造生成多项式,因为上限是b,所以每个多项式只需构造b项即可.4类牌对应4个多项式,求三次卷积求出答案.

坑点:复数类里要用long double

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 4e5 + 10;
const long double PI = acos(-1.0);
struct Complex{
    long double x, y;
    inline Complex operator+(const Complex b) const {
        return (Complex){x +b.x,y + b.y};
    }
    inline Complex operator-(const Complex b) const {
        return (Complex){x -b.x,y - b.y};
    }
    inline Complex operator*(const Complex b) const {
        return (Complex){x *b.x -y * b.y,x * b.y + y * b.x};
    }
} va[MAXN * 2 + MAXN / 2], vb[MAXN * 2 + MAXN / 2];
int lenth = 1, rev[MAXN * 2 + MAXN / 2];
int N, M;   // f 和 g 的数量
    //f g和 的系数
    // 卷积结果
    // 大数乘积
int f[MAXN],g[MAXN];
vector<LL> conv;
vector<LL> multi;
//f g
void init()
{
    int tim = 0;
    lenth = 1;
    conv.clear(), multi.clear();
    memset(va, 0, sizeof va);
    memset(vb, 0, sizeof vb);
    while (lenth <= N + M - 2)
        lenth <<= 1, tim++;
    for (int i = 0; i < lenth; i++)
        rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (tim - 1));
}
void FFT(Complex *A, const int fla)
{
    for (int i = 0; i < lenth; i++){
        if (i < rev[i]){
            swap(A[i], A[rev[i]]);
        }
    }
    for (int i = 1; i < lenth; i <<= 1){
        const Complex w = (Complex){cos(PI / i), fla * sin(PI / i)};
        for (int j = 0; j < lenth; j += (i << 1)){
            Complex K = (Complex){1, 0};
            for (int k = 0; k < i; k++, K = K * w){
                const Complex x = A[j + k], y = K * A[j + k + i];
                A[j + k] = x + y;
                A[j + k + i] = x - y;
            }
        }
    }
}
void getConv(){             //求多项式
    init();
    for (int i = 0; i < N; i++)
        va[i].x = f[i];
    for (int i = 0; i < M; i++)
        vb[i].x = g[i];
    FFT(va, 1), FFT(vb, 1);
    for (int i = 0; i < lenth; i++)
        va[i] = va[i] * vb[i];
    FFT(va, -1);
    for (int i = 0; i <= N + M - 2; i++)
        conv.push_back((LL)(va[i].x / lenth + 0.5));
}

void getMulti()             //求A*B
{
    getConv();
    multi = conv;
    reverse(multi.begin(), multi.end());
    multi.push_back(0);
    int sz = multi.size();
    for (int i = 0; i < sz - 1; i++){
        multi[i + 1] += multi[i] / 10;
        multi[i] %= 10;
    }
    while (!multi.back() && multi.size() > 1)
        multi.pop_back();
    reverse(multi.begin(), multi.end());
}

const int up = 500005;
bool check[up];
int cnt[up];

void pre()
{
    for(int i=2;i<up;++i){
        if(check[i]) continue;
        for(int j=2*i;j<up;j+=i){
            check[j] = true;
        }
    }
}

bool lack[4][up];
char str[100];

int main()
{
    pre();
    int a,b,c;
    while(scanf("%d %d %d",&a, &b, &c)==3){
        if(!a && !b && !c) continue;
        memset(lack,0,sizeof(lack));
        for(int i=1;i<=c;++i){
            int tmp = 0; scanf("%d",&tmp);
            char c; scanf("%c",&c);
            if(c=='S') lack[0][tmp] = true;
            else if(c=='H') lack[1][tmp] = true;
            else if(c=='C') lack[2][tmp] = true;
            else lack[3][tmp] = true;
        }
        N = b;
        for(int i=0;i<b;++i){
            if(check[i] && !lack[0][i]) f[i] = 1;
            else f[i] =0;
        }
        for(int i=1;i<4;++i){
            if(i>1){
                N = conv.size();
                for(int j=0;j<N;++j){
                    f[j] = conv[j];
                }
            }
            M = b;
            for(int j=1;j<b;++j){
                if(check[j] && !lack[i][j])  g[j] = 1;
                else g[j] = 0;
            }
            getConv();
        }
        for(int i=a;i<=b;++i){
            printf("%lld\n",conv[i]);
        }
        puts("");
    }
    return 0;
}
posted @ 2018-09-27 15:09  xiuwenL  阅读(212)  评论(0编辑  收藏  举报