uva12298(Super Poker II)-FFT(快速傅里叶变换)
来源:互联网 发布:json 数字 不带双引号 编辑:程序博客网 时间:2024/06/06 07:38
题目链接:Super Poker II
题意:
有一副超级扑克牌,超级扑克牌由四个花色组成,每个花色都有无数张牌,扑克牌的面值p满足条件:p的约数的个数大于2,
即扑克牌的面值为:4,6,8,9,10,12,...(不包括1和素数的自然数)
现在这幅扑克牌丢失了c张,问你从剩余的扑克牌的4个花色中各选出一张牌来,四个花色的面值之和组成一个新的值,
问分别有多少种选法能组成值a, a+1, a+2,...,b。 输出b-a+1行,每行一个数代表选法的个数。
解法:
如图,分别用多项式A(x), B(x), C(x), D(x) 表示扑克牌的四种花色,
当没有牌丢失的时候,系数全为1,当有牌丢失的时候,系数为0,比如,第一种花色的面值为6的牌丢失,则a6 = 0。
那么四个多项式求卷积
则值t的选法个数就是 x^t 的系数 zt,但是这样做复杂度非常高,是o(n^4),所以求卷积要用FFT来优化时间复杂度,
分别对多项式A(x),B(x),C(x),D(x)用FFT进行求值,时间复杂度为o(n*log(n)),将系数表示法转化为点值表示法,
然后直接相乘得到Z(x)的点值表示法,时间复杂度为o(n),然后对Z(x)进行FFT逆变换(插值操作),将点值表示法转化为
系数表示法,这样就可以将求卷积的总的时间复杂度降为o(n*log(n)),然后多项式Z(x)的系数即为答案。
另外,FFT的精度损失比较严重,而这个题需要求四个多项式的卷积,精度损失更加严重,需要用long double
代码:
# pragma comment(linker, "/STACK:1024000000,1024000000")# include <iostream># include <algorithm># include <cstdio># include <cstring># include <cmath># include <bitset>using namespace std;typedef long long ll;const long double PI = acos(-1.0);const int maxn = 500000 + 5;bitset<maxn> is_pri;struct Complex { long double x, y; Complex() : x(0.0), y(0.0) { } Complex(long double x, long double y) : x(x), y(y) { } Complex operator - (const Complex &b) const { return Complex(x - b.x, y - b.y); } Complex operator + (const Complex &b) const { return Complex(x + b.x, y + b.y); } Complex operator * (const Complex &b) const { return Complex(x * b.x - y * b.y, x * b.y + y * b.x); }} x[4][maxn];void change(Complex y[], int len) { int i, j, k; for (i = 1, j = len / 2; i < len - 1; i++) { if (i < j) swap(y[i], y[j]); k = len / 2; while (j >= k) { j -= k; k /= 2; } if (j < k) j += k; }}void fft(Complex y[], int len, int on) { change(y, 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 = y[k]; Complex t = w * y[k + h / 2]; y[k] = u + t; y[k + h / 2] = u - t; w = w * wn; } } } if(on == -1) for (int i = 0; i < len; i++) y[i].x /= len;}void init() { is_pri.set(); is_pri[0] = is_pri[1] = 0; int t = sqrt(maxn + 0.5); for (int i = 2; i <= t; ++i) if (is_pri[i]) for (int j = i * i; j < maxn; j += i) is_pri[j] = 0;}int to(char ch) { if (ch == 'S') return 0; else if (ch == 'H') return 1; else if (ch == 'C') return 2; else if (ch == 'D') return 3;}int main(void){ int a, b, c; init(); while (~scanf("%d %d %d", &a, &b, &c) && (a || b || c)) { int len0 = b + 1, len = 1; while (len < len0) len <<= 1; len <<= 2; for (int i = 0; i < 4; ++i) { x[i][0] = x[i][1] = Complex(0.0, 0.0); for (int j = 2; j < len0; ++j) { if (!is_pri[j]) x[i][j] = Complex(1.0, 0.0); else x[i][j] = Complex(0.0, 0.0); } for (int j = len0; j < len; ++j) x[i][j] = Complex(0.0, 0.0); } for (int i = 0; i < c; ++i) { int val; char ch; scanf("%d%c", &val, &ch); x[to(ch)][val].x = 0.0; } for (int i = 0; i < 4; ++i) fft(x[i], len, 1); for (int i = 0; i < len; ++i) x[0][i] = x[0][i] * x[1][i] * x[2][i] * x[3][i]; fft(x[0], len, -1); for (int i = a; i <= b; ++i) printf("%lld\n", (ll)(x[0][i].x + 0.5)); puts(""); } return 0;}
阅读全文
1 0
- uva12298(Super Poker II)-FFT(快速傅里叶变换)
- UVA12298 Super Poker II 递推
- 【UVa12298】 Super Joker II 【FFT】【生成函数】
- UVA 12298 Super Poker II(FFT)
- [UVA 12298 Super Poker II]FFT/NTT
- UVA 12298 Super Poker II(FFT)
- UVA 12298 Super Poker II (FFT + long double)
- UVA 12298 Super Poker II
- UVA 12298 Super Poker II
- 快速傅里叶变换(FFT)(ZZ)
- FFT快速傅里叶变换;
- 快速傅里叶变换(FFT)
- 关于FFT快速傅里叶变换
- FFT快速傅里叶变换
- FFT - 快速傅里叶变换
- 快速傅里叶变换(FFT)
- 快速傅里叶变换(FFT)
- GSL快速傅里叶变换FFT
- Python脚本 —Windows下文件备份
- Android TextView使用SpannableString设置复合文本的方法
- linux tty1-7理解
- 仿照百度网盘的分析
- Java学习记录–泛型擦除分析
- uva12298(Super Poker II)-FFT(快速傅里叶变换)
- POJ-3233 Matrix Power Series
- 【多校训练】hdu 6168 Numbers
- iOS开发---WKWebView加载不受信任的https
- Android APK加固(加壳)工具
- 简单控件事件处理
- 2、重识MySQL-MySQL Linux下RPM 安装
- 编写App测试用例的关注点
- 200行的Node爬虫花了半天的时间把网易云上的30万首歌曲信息都抓取回来