UVA 12298 Super Poker II

4 篇文章 0 订阅

转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents

题意

给定一些扑克牌,value为合数,其中丢了c张牌,问这些扑克牌选四色(必须一个花色选一张)能组成n的方案数

思路

素筛,然后构造四个多项式(每个花色一个),去掉丢失的牌
将这四个多项式相乘,利用FFT,得到的就是方案数了
注意:精度会爆double,要用long double
最后结果会爆int,要用long long
输出不能用%I64d,要用%lld


Result: Accepted Time: 170ms
具体代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const long double PI = acos(-1);
const int maxn = 5e4+5;//maxn = max(len1,len2)
const int maxm = 4*maxn;//k是>=maxn的最小的2的幂,maxm=2*k
int len1,len2,len;//len1,len2分别为两个多项式的最高次数+1
ll S[maxn],H[maxn],C[maxn],D[maxn];
char str[20];
ll num1[maxm],num2[maxm];
ll ans[maxm];
bool vis[maxn];
int a,b,c,x,y;
void sieve()
{
    int m = sqrt(maxn+0.5);
    memset(vis, 0, sizeof vis);
    for(int i = 2; i <= m; i++) if(!vis[i])
        for(int j = i*i; j < maxn; j+=i) vis[j] = 1;
}
//复数结构体
struct Complex
{
    long double x, y;//实部为x,虚部为y
    Complex(long double x=0,long double y=0):x(x),y(y){}
    Complex operator+(const Complex &rhs) const { return Complex(x+rhs.x, y+rhs.y);}
    Complex operator-(const Complex &rhs) const { return Complex(x-rhs.x, y-rhs.y);}
    Complex operator*(const Complex &rhs) const { return Complex(x*rhs.x-y*rhs.y,x*rhs.y+y*rhs.x);}
};
Complex x1[maxm],x2[maxm];
/*
进行FFT和IFFT前的反转变换。
将位置i和(i二进制反转后位置)互换。
len必须取2的幂
*/
void change(Complex *x, int len)
{
    Complex t;
    for(int i = 1, j = len/2; i < len-1; i++)
    {
        //交换下标互反的元素,i<j保证交换一次
        //i做正常的+1,j做反转的+1,始终保持i和j是反转的
        if(i < j)
        {
            t = x[i];
            x[i] = x[j];
            x[j] = t;
        }
        int k = len / 2;
        while(j >= k)
        {
            j -= k;
            k >>= 1;
        }
        if(j < k) j += k;
    }
}
/*
做FFT
len必须为2的幂
on==1时是DFT,on==-1时是IDFT
*/
void fft(Complex *x, int len, int on)
{
    change(x, len);
    for(int h = 2; h <= len; h <<= 1)
    {
        Complex wn(cos(-on*2*PI/h), sin(-on*2*PI/h));
        for(int j = 0; j < len; j += h)
        {
            Complex w(1, 0);
            for(int k = j; k < j+h/2; k++)
            {
                Complex u = x[k];
                Complex t = w*x[k+h/2];
                x[k] = u+t;
                x[k+h/2] = u-t;
                w = w*wn;
            }
        }
    }
    if(on == -1)
        for(int i = 0; i < len; i++) x[i].x /= len;
}
void workFFT(ll *xx,int len1,ll *yy,int len2,ll *num)
{
    len = 1;
    memset(x1,0,sizeof x1);
    memset(x2,0,sizeof x2);
    memset(num,0,sizeof num);
    while(len < len1*2 || len < len2*2) len <<=1;
    for(int i = 0; i < len; i++)
            x1[i] =  x2[i] = Complex(0,0);
    for(int i = 0; i < len1; i++) x1[i] = Complex(xx[i],0);
    for(int i = 0; i < len2; i++) x2[i] = Complex(yy[i],0);
    fft(x1,len,1);
    fft(x2,len,1);
    for(int i = 0; i < len; i++) x1[i] = x1[i]*x2[i];
    fft(x1,len,-1);
    for(int i = 0; i < len; i++) num[i] = (ll)(x1[i].x+0.5);
}
int main()
{
    sieve();
    while(~scanf("%d%d%d",&a,&b,&c),a+b+c)
    {
        for(int i=2;i<=b;i++)
            if(vis[i])
        {
            //cout<<i<<endl;
            S[i]=1;
            H[i]=1;
            C[i]=1;
            D[i]=1;
        }
        for(int i=1;i<=c;i++)
        {
            scanf("%s",str);
            x = strlen(str);
            y = str[0]-'0';
            for(int i=1;i<x-1;i++)
                y = y*10 + str[i]-'0';
            if(str[x-1]=='H') H[y]=0;
            if(str[x-1]=='S') S[y]=0;
            if(str[x-1]=='C') C[y]=0;
            if(str[x-1]=='D') D[y]=0;
        }
        workFFT(H,b+1,S,b+1,num1);
        workFFT(C,b+1,D,b+1,num2);
        workFFT(num1,b+1,num2,b+1,ans);
        for(int i=a;i<=b;i++)
            printf("%lld\n",ans[i]);
        printf("\n");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值