zoukankan      html  css  js  c++  java
  • UVa12298 Super Poker II(母函数 + FFT)

    题目

    Source

    http://acm.hust.edu.cn/vjudge/problem/23590

    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.

    Sample Input

    12 20 2
    4S 6H
    0 0 0

    Sample Output

    0
    0
    0
    0
    0
    0
    1
    0
    3

    分析

    题目大概说有一副数字是合数的扑克,花色同样有4种,现在已知里面缺少了c张牌,问从各个花色中各选一张,分别有多少种方案使得四张牌的和等于[a,b]中的各个数字。

    母函数,构造四个多项式,分别对应各个花色,指数表示牌上面的数字,系数表示该牌的数量(0或1),然后四个多项式乘积中指数等于[a,b]的系数就是答案了。

    由于指数达到了50000,所以用FFT进行多项式乘法。

    这题还是很容易的,不过还是WA了——因为精度。。要用long double。

    代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define MAXN 277777
    const long double PI=acos(-1.0);
    
    struct Complex{
    	long double real,imag;
    	Complex(long double _real,long double _imag):real(_real),imag(_imag){}
    	Complex(){}
    	Complex operator+(const Complex &cp) const{
    		return Complex(real+cp.real,imag+cp.imag);
    	}
    	Complex operator-(const Complex &cp) const{
    		return Complex(real-cp.real,imag-cp.imag);
    	}
    	Complex operator*(const Complex &cp) const{
    		return Complex(real*cp.real-imag*cp.imag,real*cp.imag+cp.real*imag);
    	}
    	void setValue(long double _real=0,long double _imag=0){
    		real=_real; imag=_imag;
    	}
    };
    
    int len;
    Complex wn[MAXN],wn_anti[MAXN];
    
    void FFT(Complex y[],int op){
    	for(int i=1,j=len>>1,k; i<len-1; ++i){
    		if(i<j) swap(y[i],y[j]);
    		k=len>>1;
    		while(j>=k){
    			j-=k;
    			k>>=1;
    		}
    		if(j<k) j+=k;
    	}
    	for(int h=2; h<=len; h<<=1){
    		Complex Wn=(op==1?wn[h]:wn_anti[h]);
    		for(int i=0; i<len; i+=h){
    			Complex W(1,0);
    			for(int j=i; j<i+(h>>1); ++j){
    				Complex u=y[j],t=W*y[j+(h>>1)];
    				y[j]=u+t;
    				y[j+(h>>1)]=u-t;
    				W=W*Wn;
    			}
    		}
    	}
    	if(op==-1){
    		for(int i=0; i<len; ++i) y[i].real/=len;
    	}
    }
    void Convolution(Complex A[],Complex B[],int n){
    	for(len=1; len<(n<<1); len<<=1);
    	for(int i=n; i<len; ++i){
    		A[i].setValue();
    		B[i].setValue();
    	}
    	
    	FFT(A,1); FFT(B,1);
    	for(int i=0; i<len; ++i){
    		A[i]=A[i]*B[i];
    	}
    	FFT(A,-1);
    }
    
    bool isComNum[55555];
    bool exist[4][55555];
    Complex A[4][MAXN];
    
    int main(){
    	for(long long i=2; i<55555; ++i){
    		if(!isComNum[i]){
    			for(long long j=i*i; j<55555; j+=i){
    				isComNum[j]=1;
    			}
    		}
    	}
    	for(int i=0; i<MAXN; ++i){
    		wn[i].setValue(cos(2.0*PI/i),sin(2.0*PI/i));
    		wn_anti[i].setValue(wn[i].real,-wn[i].imag);
    	}
    	int a,b,c;
    	while(scanf("%d%d%d",&a,&b,&c)==3 && (a||b||c)){
    		memset(exist,1,sizeof(exist));
    		char ch; int x;
    		while(c--){
    			scanf("%d",&x); scanf(" %c",&ch);
    			if(ch=='S') exist[0][x]=0;
    			else if(ch=='H') exist[1][x]=0;
    			else if(ch=='C') exist[2][x]=0;
    			else exist[3][x]=0;
    		}
    		for(int i=0; i<4; ++i){
    			for(int j=0; j<b; ++j){
    				if(isComNum[j] && exist[i][j]) A[i][j].setValue(1);
    				else A[i][j].setValue(0);
    			}
    		}
    		Convolution(A[0],A[1],b);
    		Convolution(A[2],A[3],b);
    		Convolution(A[0],A[2],b*2);
    		for(int i=a; i<=b; ++i){
    			printf("%lld
    ",(long long)(A[0][i].real+0.5));
    		}
    		putchar('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    SQL server中自定义排序
    安装nodejs版本模块报错notsup Unsupported platform for n
    vue项目中一些标签直接放在<template>下会报错Failed to compile with 1 errors
    vue中使用element-ui出现Couldn't find preset "es2015" relative to directory
    解决两个相邻的span,或者input和button中间有间隙,在css中还看不到
    VsCode中代码折叠快捷键
    npm 操作代码
    vue项目打包成html,在本地点击直接能打开
    地图只显示部分区域,其他地区不显示
    vs里颜色显示块怎样显示
  • 原文地址:https://www.cnblogs.com/WABoss/p/5835398.html
Copyright © 2011-2022 走看看