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.

我有一副超级扑克包含无数张牌,如果数字是正合数的话,那就有四种牌:黑桃(S)、红桃(H)、梅花(C)、方片(D)。

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).

比如6有4个因子(1,2,3,6)所以它是合数;7只有两个(1,7)那就不是合数。

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:

给定一个整数n,从四种花色各选一张牌,使得四张牌点数和为n,求解有多少种选法组合。比如n=24时,其中的一种选法可以为24=4+6+4+10,如下图所示:

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.

不幸的是有的牌丢失了,样例会给出哪些丢了。并且为了题目更加因吹斯听,实际上不是给你n,而是给两个数a、b,输出所有n=a、n=a+1、n=a+2、……、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.

输入有多组数据,每组数据第一行三个整数a、b、c,a、b如上,c为丢失卡牌数;第二行给出c个具体的卡牌为丢失的。abc均为0时输入结束。

Output
For each test case, print p integers, one in each line. 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

拜早年啦!年夜是刷题,还是边看番边刷题,还是带亲戚家小孩刷题啊?

口胡思路:

先以只有两色四张牌的简单题为例。假如第一个花色S有4和6两个点数,则可以用一个多项式表示所有可选情况:x^4 + x^6;第二个花色H有8和10两个点数,可用:x^8 + x^10表示。

我们将这两式相乘得(x^4 + x^6)(x^8 + x^10) = x^12 + 2 * x^14 + x^16,这个结果代表的意义就是:和为12的组合有1种,和为14的组合有2种(4S+10H或6S+8H),和为16的有1种。

好,那么对应到最开始的这道题目上来,就是稍微复杂了一点。对于每个花色,x的次幂为质数时系数为0,即多项式中只存在合数项。然后合数中也会有丢失的,其系数也置零。接下来四个多项式相乘即可,最终的多项式中x的次幂为n的项的系数,就是和为n的组合数。

事实上,这是离散数学中的一个小知识点,如题,是生成函数的一个简单应用,在此处帮大家复习一下。

另外,两多项式相乘的朴素做法显然是O(n^2)的,用FFT或者NTT加速成nlogn喽。不过快速傅里叶变换和数论变换不是一两句话可以口胡明白的,也不是本文想讲的知识,姑且略去……

最后,如果自己手写的FFT而没用complex库里的复数运算的话,这题卡精度,要用long double。

诸君来看代码吧:

 #include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std; const int maxn = ;
const long double PI = acos(-1.0); struct Complex {
long double x, y;
Complex(long double a = , long double b = ):x(a), y(b){}
};
//手写复数运算
Complex operator + (Complex A, Complex B) { return Complex(A.x + B.x, A.y + B.y); }
Complex operator - (Complex A, Complex B) { return Complex(A.x - B.x, A.y - B.y); }
Complex operator * (Complex A, Complex B) { return Complex(A.x * B.x - A.y * B.y, A.x * B.y + A.y * B.x); } Complex n[maxn * ], m[maxn * ];//像线段树一样要开4倍
int r[maxn * ], l, limit, nl;
/*---以上为FFT所需部分---*/ int a, b, c;//abc含义见题面
bool composite[maxn];//合数记录
bool lost[][maxn];//卡牌丢失记录 void init(int n) {//求50000以内的合数
int m = int(sqrt(n) + 0.5);
for (int i = ; i <= m; i++)
if (!composite[i])
for (int j = i * i; j <= n; j += i)
composite[j] = ;
} const char *ss = "SHCD";
int idx(char c) {//巧得丢失字符位置
return strchr(ss, c) - ss;
} /*--以下为一个普通的FFT板子--*/
void fft_init() {
limit = , l = ;
while (limit < *(b + )) {
limit <<= ;
l++;
} for (int i = ; i < limit; i++)
r[i] = (r[i>>] >> ) | ((i&) << (l-));
} void fft(Complex *A, int type) {
for (int i = ; i < limit; i++)
if (i < r[i])
swap(A[i], A[r[i]]); for (int mid = ; mid < limit; mid <<= ) {
Complex Wn(cos(PI / mid), type * sin(PI / mid));
for (int R = mid << , j = ; j < limit; j += R) {
Complex w(, );
for (int k = ; k < mid; k++, w = w * Wn) {
Complex x = A[j+k], y = w * A[j+k+mid];
A[j+k] = x + y;
A[j+k+mid] = x - y;
}
}
}
} void Fourier(Complex *A, Complex *B) {
fft(A, );
fft(B, );
for (int i = ; i < limit; i++)
A[i] = A[i] * B[i];
fft(A, -);
for (int i = ; i < nl + b + ; i++)
A[i].x /= limit, A[i].y = 0.0;
}
/*---FFT结束---*/ int main() {
init();//求5万以内合数
while (~scanf("%d%d%d", &a, &b, &c) && a) {
memset(lost, false, sizeof(lost));//丢牌数组
for (int i = ; i < c; i++) {
int temp; char ch;
scanf("%d%c", &temp, &ch);
lost[idx(ch)][temp] = ;//这张牌丢了
} n[].x = 1.0, n[].y = 0.0;//同下方m数组注释
nl = ;
fft_init();//这个东西反复调用没意义就先拿出来了
for (int i = ; i < ; i++) {
//n是上一轮结束时的多项式结果,nl是多项式n的长度
//答案只要求a到b的多项式系数,所以次幂为b以上可以置零
for (int j = nl; j <= limit; j++)
n[j].x = n[j].y = 0.0;
//m数组用来表示当前花色的多项式,所以先全置零
for (int j = ; j <= limit; j++)
m[j].x = m[j].y = 0.0; for (int j = ; j <= b; j++) {
if (composite[j] && !lost[i][j])
m[j].x = 1.0, m[j].y = 0.0;
//将这个合数的多项式系数设为复数(1 + 0*i),即实数的1
}
Fourier(n, m);//n和m这两个多项式相乘
nl = b + ;//b+1的原因是常数项也是一项
} for (int i = a; i <= b; i++)//x为实数项,即系数
printf("%lld\n", (long long)(n[i].x + 0.5));
puts("");
}
return ;
}

UVa12298(生成函数的简单应用+FFT)的更多相关文章

  1. uva12298(生成函数)

    生成函数的一般应用: #include<iostream> #include<cstring> #include<cmath> #include<cstdio ...

  2. 简单的 FFT 变形 - BZOJ 2194

    「BZOJ2194」快速傅立叶之二 2015年4月29日3,8300 Description 请计算C[k]=sigma(a[i]*b[i-k]) 其中 k < = i < n ,并且有 ...

  3. FFT的物理意义

    来源:学步园 FFT(Fast Fourier Transform,快速傅立叶变换)是离散傅立叶变换的快速算法,也是我们在数字信号处理技术中经常会提到的一个概念.在大学的理工科课程中,在完成高等数学的 ...

  4. BZOJ.4909.[SDOI2017]龙与地下城(正态分布 中心极限定理 FFT Simpson积分)

    BZOJ 洛谷 https://www.luogu.org/blog/ShadowassIIXVIIIIV/solution-p3779# 正态分布 正态分布是随机变量\(X\)的一种概率分布形式.它 ...

  5. 2016 MIPT Pre-Finals Workshop Taiwan NTU Contest

    2016弱校联盟十一专场10.5 传送门 A. As Easy As Possible 假设固定左端点,那么每次都是贪心的匹配\(easy\)这个单词. 从\(l\)开始匹配的单词,将\(y\)的位置 ...

  6. bzoj2487: Super Poker II

    Description I have a set of super poker cards, consisting of an infinite number of cards. For each p ...

  7. 『TensorFlow』SSD源码学习_其四:数据介绍及TFR文件生成

    Fork版本项目地址:SSD 一.数据格式介绍 数据文件夹命名为VOC2012,内部有5个子文件夹,如下, 我们的检测任务中使用JPEGImages文件夹和Annotations文件夹. JPEGIm ...

  8. [USACO19DEC]Tree Depth P

    题意 求逆序对为\(k\)的\(n\)排列中,生成的笛卡尔数,每个位置的深度和.\(n\le 300\) 做法 设\(f_{k}\)为\(n\)排列中逆序对为\(k\)的个数,其生成函数为:\[\pr ...

  9. bzoj 3513 [MUTC2013]idiots FFT 生成函数

    [MUTC2013]idiots Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 806  Solved: 265[Submit][Status][Di ...

随机推荐

  1. SPOJ1811 LCS SAM

    后缀自动机简单题. 其主要思路是,先对第一个字符串建立后缀自动机,把第二个串放在上面匹配, 若当前状态s有字符x的转移,直接转移len=step+1. 若当前状态s没有向字符x的转移,退回pres检查 ...

  2. 简述arp协议的工作原理

    在每台安装有TCP/IP协议的电脑里都有一个ARP缓存表,表里的IP地址与MAC地址是一一对应的,如: 我们以主机A(192.168.1.5)向主机B(192.168.1.1)发送数据为例.当发送数据 ...

  3. win8系统在安装软件时安装framework3.5失败的解决办法

    win8系统在,许多软件都需求安装framework3.5,但是很多用户都是安装失败,联网失败,据网上的许多人说有用cmd输入命令,然后到100%,就会成功安装framework3.5(如这个方法:w ...

  4. scroll或是其子类被添加进view时,界面自动上移

    开发中经常会遇到ViewController添加scroll或是其子类被添加进controller.view时,scroll会自动下移大概64像素 解决: self.edgesForExtendedL ...

  5. C++打印变量地址

    %p专门用来打印变量的以十六进制表示的地址: #include<iostream> using namespace std; int main() { ; printf("a的地 ...

  6. TensorFlow 图像预处理(一) 图像编解码,图像尺寸调整

    from: https://blog.csdn.net/chaipp0607/article/details/73029923 TensorFlow提供了几类图像处理函数,下面介绍图像的编码与解码,图 ...

  7. CISCO-更新路由器IOS

    1,查看flash,复制IOS文件名,再上传IOS 2,传送完毕查看下flash Router# show flash: 查看flash中的信息 Directory of flash: 1 -rw- ...

  8. 属性(@property)的修饰词有哪些,各自是什么作用,在哪种情况下用?

       之前面试了几家公司,都会问到这个基础的问题,以前,没有怎么注意,所以答的很混乱,所以查了查网上的资料,特意整理了一份.   常见修饰词有:assign.weak.strong.retain.co ...

  9. npm --- Node.js包管理器

    目录 1. 安装Node.js 2. 运行npm 3. npm介绍 3.1 安装插件 3.2 更新插件 3.3 卸载插件 3.4 查看当前目录中的插件列表 4. 使用cnpm 4.1 安装 npm( ...

  10. K个联通块

    题意: 有一张无重边的无向图, 求有多少个边集,使得删掉边集里的边后,图里恰好有K个联通块. 解法: 考虑dp,$h(i,S)$表示有$i$个联通块,点集为$S$的图的个数,$g(S)$表示点集为S的 ...