题目要求牌的组合数,可以转化为多项式乘法。
设某种花色对应的多项式为
的指数则可以表示扑克牌的点数,系数则可以赋值为0或1,来表示该点数是否存在。
四种花色,则一共有4条多项式,将这些多项式乘起来,结果的
那么现在的问题是如何进行多项式的乘法,直接暴力
FFT的原理和实现的话推荐看这位小哥的视频,他的蝴蝶操作讲得很细。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <stack>
#include <bitset>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <complex>
#include <algorithm>
#define FOP freopen("data.txt","r",stdin)
#define FOP2 freopen("data1.txt","w",stdout)
#define inf_LL 4223372036854775807
#define inf 0x3f3f3f3f
#define mod 1000000007
#define PI acos(-1.0)
#define LL long long
using namespace std;
typedef complex<double> CD;
inline void FFT(vector<CD> &a, bool inverse) {
int n = a.size();
// 原地 bit reversal
for(int i = 0, j = 0; i < n; i++) {
if(j > i) swap(a[i], a[j]);
int k = n;
while(j&(k >>= 1)) j &= ~k;
j |= k;
}
double pi = inverse ? -PI : PI;
for(int step = 1; step < n; step <<= 1) {
double alpha = pi / step; // alpha = 2*PI/nn
for(int k = 0; k < step; k++) {
CD omegak = exp(CD(0, alpha*k));
for(int Ek = k; Ek < n; Ek += step<<1) {
int Ok = Ek + step;
CD t = omegak * a[Ok];
a[Ok] = a[Ek] - t;
a[Ek] += t;
}
}
}
if(inverse) for(int i = 0; i < n; i++) a[i] /= n;
}
inline vector<double> operator * (const vector<double>& v1, const vector<double>& v2) {
int s1 = v1.size(), s2 = v2.size(), S = 2;
while(S < (s1+s2)) S <<= 1;
vector<CD> a(S,0), b(S,0); // 把FFT的输入长度补成2的幂,不小于v1和v2的长度之和
for(int i = 0; i < s1; i++) a[i] = v1[i];
FFT(a, false);
for(int i = 0; i < s2; i++) b[i] = v2[i];
FFT(b, false);
for(int i = 0; i < S; i++) a[i] *= b[i];
FFT(a, true);
vector<double> res(s1+s2-1);
for(int i = 0; i < s1+s2-1; i++) res[i] = a[i].real();
return res;
}
const int maxn = 50010;
int vis[maxn];
void sieve(int n)
{
int m = (int)sqrt(n+0.5);
for(int i = 2; i <= m; i++) if(!vis[i])
for(int j = i*i; j <= n; j+=i) vis[j] = 1;
}
int ids(char c) {
if(c == 'S') return 0;
if(c == 'H') return 1;
if(c == 'C') return 2;
if(c == 'D') return 3;
else return inf;
}
int a, b, c;
bool lost[4][maxn];
int main() {
sieve(50000);
while(scanf("%d%d%d", &a, &b, &c) == 3 && a) {
memset(lost, 0, sizeof(lost));
int p; char s;
while(c--) {
scanf("%d%c", &p, &s);
lost[ids(s)][p] = 1;
}
vector<double> ans(1,1), vec;
for(int i = 0; i < 4; i++) {
vec.clear();
vec.resize(b+1, 0);
for(int j = 4; j <= b; j++) {
if(!lost[i][j] && vis[j]) vec[j] = 1.0;
}
ans = ans * vec;
ans.resize(b+1);
}
for(int i = a; i <= b; i++) {
printf("%.f\n", fabs(ans[i]));
}
printf("\n");
}
return 0;
}