转载请注明出处,谢谢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");
}
}