Super Poker II UVA - 12298 FFT + 生成函数

Description

I have a set of super poker cards, consisting of an infinite number of cards. For each positive composite integer p, there
are exactly four cards whose value is p: Spade(S), Heart(H), Club(C) and Diamond(D). There are no cards of other values.
By “composite integer”, we mean integers that have more than 2 divisors. For example, 6 is a composite integer, since it
has 4 divisors: 1, 2, 3, 6; 7 is not a composite number, since 7 only has 2 divisors: 1 and 7. Note that 1 is not composite
(it has only 1 divisor).
 
Given a positive integer n, how many ways can you pick up exactly one card from each suit (i.e. exactly one spade card,
one heart card, one club card and one diamond card), so that the card values sum to n? For example, if n=24, one way is
4S+6H+4C+10D, shown below:

 

 

 

Unfortunately, some of the cards are lost, but this makes the problem more interesting. To further make the problem even
more interesting (and challenging!), I’ll give you two other positive integers a and b, and you need to find out all the
answers for n=a, n=a+1, …, n=b. 

Input

The input contains at most 25 test cases. Each test case begins with 3 integers a, b and c, where c is the number of lost
cards. The next line contains c strings, representing the lost cards. Each card is formatted as valueS, valueH, valueC or
valueD, where value is a composite integer. No two lost cards are the same. The input is terminated by a=b=c=0. There
will be at most one test case where a=1, b=50,000 and c<=10,000. For other test cases, 1<=a<=b<=100, 0<=c<=10. 
 

Output

For each test case, print b-a+1 integers, one in each line. Since the numbers might be large, you should output each
integer modulo 1,000,000. Print a blank line after each test case. 

题解:生成函数+FFT优化多项式乘法. 

对于每种牌,构造一个生成函数,4 个生成函数相乘,输出对应项数即可. 

#include<bits/stdc++.h>     
#define maxn 1000000    
#define ll long long 
#define double long double    
#define setIO(s) freopen(s".in","r",stdin), freopen(s".out","w",stdout) 
using namespace std; 
 
struct cpx
{
    double x,y; 
    cpx(double a=0,double b=0){x=a,y=b;} 
}; 
cpx operator+(cpx a,cpx b) { return cpx(a.x+b.x,a.y+b.y); }
cpx operator-(cpx a,cpx b) { return cpx(a.x-b.x,a.y-b.y); } 
cpx operator*(cpx a,cpx b) { return cpx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x); } 
 
namespace FFT
{
    const double pi=acos(-1);  
    void FFT(cpx *a,int n,int flag)
    {
        for(int i = 0,k = 0;i < n; ++i)
        {
            if(i > k) swap(a[i],a[k]);
            for(int j = n >> 1;(k^=j)<j;j>>=1);
        }
        for(int mid=1;mid<n;mid<<=1)
        {
            cpx wn(cos(pi/mid),flag*sin(pi/mid)),x,y; 
            for(int j=0;j<n;j+=(mid<<1)) 
            {
                cpx w(1,0); 
                for(int k=0;k<mid;++k) 
                {
                    x = a[j+k],y=w*a[j+mid+k]; 
                    a[j+k]=x+y; 
                    a[j+mid+k]=x-y; 
                    w=w*wn; 
                }
            }
        } 
    }      
}; 
 
cpx arr[maxn], brr[maxn], crr[maxn], drr[maxn];
int vis[maxn],prime[maxn],non_prime[maxn]; 
int tot,cas; 
char str[100]; 
int idx(char c)
{
    if(c=='S') return 0;
    if(c=='H') return 1; 
    if(c=='C') return 2;
    if(c=='D') return 3;  
}
void update()
{
    scanf("%s",str+1); 
    int len=strlen(str+1); 
    int num=0; 
    for(int i=1;i<=len;++i) 
    {
        if(str[i]>='0' && str[i]<='9') 
            num=num*10+str[i]-'0'; 
        else
        {
            int cur=idx(str[i]); 
            switch(cur)
            {
                case 0 : { arr[num].x=0;  break;}
                case 1 : { brr[num].x=0;  break;}
                case 2 : { crr[num].x=0;  break;}
                case 3 : { drr[num].x=0;  break;}
            }
        }
    }     
}
void get_number()
{  
    for(int i=2;i<=100000;++i) 
    {
        if(!vis[i]) prime[++tot]=i;  
        for(int j=1;j<=tot&&prime[j]*i*1ll<=1ll*100000;++j) 
        {
            vis[prime[j]*i]=1; 
            if(i%prime[j]==0) break; 
        } 
    }
    tot=0; 
    for(int i=2;i<=100000;++i) if(vis[i]) non_prime[++tot]=i; 
}  
int main()
{
    // setIO("input");  
    get_number(); 
    for(cas=1; ;++cas)
    {
        int l,r,o,len=1;  
        scanf("%d%d%d",&l,&r,&o);  
 
        if(l==0&&r==0&&o==0) break; 
 
        while(len<=r) len<<=1; 
        
        len<<=2;    
        for(int i=1;i<=r;++i) arr[i]=cpx(vis[i],0); 
        for(int i=1;i<=r;++i) brr[i]=cpx(vis[i],0); 
        for(int i=1;i<=r;++i) crr[i]=cpx(vis[i],0);  
        for(int i=1;i<=r;++i) drr[i]=cpx(vis[i],0); 
        while(o--)  update();       
        // for(int i=0;i<len;++i) printf("%d %d\n",(int)arr[i].x,(int)arr[i].y);         
        FFT::FFT(arr,len, 1), FFT::FFT(brr,len, 1), FFT::FFT(crr,len, 1), FFT::FFT(drr,len, 1); 
        for(int i=0;i<len;++i) 
        { 
            arr[i]=arr[i]*brr[i]*crr[i]*drr[i];      
        }
        FFT::FFT(arr,len,-1);              
        for(int i=l;i<=r;++i) printf("%lld\n", (ll)(arr[i].x/len+0.1)%1000000); 
        printf("\n"); 
        for(int i=0;i<=len+233;++i) arr[i]=brr[i]=crr[i]=drr[i]=cpx(0,0); 
    }
    return 0; 
}

  

转载于:https://www.cnblogs.com/guangheli/p/11002020.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值