追逐青春的梦想,怀着自信的心,永不放弃
1、假设有x1个字母A,x2个字母B,……,x26个字母Z,同时假设字母A的价值为1,字母B的价值为2,……,字母Z的价值为26。那么,对于给定的字母,可以找到多少价值不大于50的单词呢?单词的价值就是组成一个单词的所有字幕的价值之和。比如,单词ACM的价值是1+3+14=18(组成的单词与排列顺序无关,比如ACM和MCA认为是同一单词)。
输入:输入首先是一个整数N,代表测试实例的个数。然后包括N行数据,每行包括26个不大于20的整数x1,x2,……,x26。
输出:对于每个测试实例,请输出能找到的总价值不大于50的单词数,每个势力的输出占一行。
输入样例:
2
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
9 2 6 2 10 2 2 5 6 1 0 2 7 0 2 2 7 5 10 6 10 2 10 6 1 9
样例输出:
7
379297
分析:转化为求x的指数小于等于50的系数和
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<map>
#include<stack>
#include<queue>
#include<set>
#include<sstream>
#include<ctime>
#include<algorithm>
#include<bits/stdc++.h>
#include<sstream>
#include<list>
#include<cmath>
#include<deque>
#include<cstdlib>
using namespace std;
const int maxn = 10086;
#define inf 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long LL;
void anhangduru(){
string line;
while(getline(cin,line)){
int sum=0;
int x;
stringstream ss(line);
while(ss>>x){sum+=x;}//按空格读入
}
}//按行读入
//加上符号重载
int main()
{
// ios::sync_with_stdio(0);//输入输出挂
int n;
scanf("%d",&n);
int a[60],b[60];
while(n--){
int num;
for(int i=0;i<=60;i++){
a[i]=0;
b[i]=0;
}
a[0]=1;
for(int i=1;i<=26;i++){
scanf("%d",&num);
if(num==0)continue;
for(int j=0;j<=50;j++)
for(int k=0;k<=num&&k*i+j<=50;k++)
b[k*i+j]+=a[j];
for(int j=0;j<=50;j++){
a[j]=b[j];
b[j]=0;
}
}
int tot = 0;
for(int i=1;i<=50;i++){
tot += a[i];
}
printf("%d\n",tot);
}
return 0;
}
这段代码的核心是:
a[0]=1;
for(int i=1;i<=26;i++){
scanf("%d",&num);
if(num==0)continue;
for(int j=0;j<=50;j++)
for(int k=0;k<=num&&k*i+j<=50;k++)
b[k*i+j]+=a[j];
for(int j=0;j<=50;j++){
a[j]=b[j];
b[j]=0;
}
}
2、给一个正整数N,我们定义这样一个等式:
因此,当N等于4时结果是5。
输入:输入包含几组测试样例。每一组测试样例包含一个正整数N(1<=N<=120)。
输出:对于每个测试实例,请输出能找到的不同等式的个数,每个实例的输出占一行。
样例输入:
4
10
20
样例输出:
5
42
627
分析:求正整数N的拆分数。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<map>
#include<stack>
#include<queue>
#include<set>
#include<sstream>
#include<ctime>
#include<algorithm>
#include<bits/stdc++.h>
#include<sstream>
#include<list>
#include<cmath>
#include<deque>
#include<cstdlib>
using namespace std;
const int maxn = 10086;
#define inf 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long LL;
void anhangduru(){
string line;
while(getline(cin,line)){
int sum=0;
int x;
stringstream ss(line);
while(ss>>x){sum+=x;}//按空格读入
}
}//按行读入
//加上符号重载
int main()
{
// ios::sync_with_stdio(0);//输入输出挂
int n;
int a[121],b[121];
while(~scanf("%d",&n)){
for(int i=0;i<=n;i++){
a[i]=1;
b[i]=0;
}
for(int i=2;i<=n;i++){
for(int j=0;j<=n;j++){
for(int k=0;k+j<=n;k+=i){
b[k+j]+=a[j];
}
}
for(int j=0;j<=n;j++){
a[j]=b[j];
b[j]=0;
}
}
printf("%d\n",a[n]);
}
return 0;
}
这段代码的关键点:
for(int i=2;i<=n;i++){
for(int j=0;j<=n;j++){
for(int k=0;k+j<=n;k+=i){
b[k+j]+=a[j];
}
}
for(int j=0;j<=n;j++){
a[j]=b[j];
b[j]=0;
}
}
3、Ferrers图像
定理1:
整数n拆分成k个数的和的拆分数,与数n拆分成最大数为k的拆分数相等
定理2:
整数n拆分成最多不超过m个数的和的拆分数,与n拆分成最大不超过m的拆分数相等
定理3:
整数n拆分成互不相同的若干奇数的和的拆分数,与n拆分成自共轭的Ferrers图像的拆分数相等
定理4:
正整数n拆分成不超过k个数的和的拆分数,等于将n+k拆分成敲好k个数的拆分数
4、指数型母函数
有n种物品,并且知道每种物品的数量。要求从中选出m件物品的排列数。例如有两种物品A,B,并且数量都是1,从中选2件物品,则排列有”AB”,”BA”两种。
输入:每组输入数据有两行,第一行是二个数n,m(1<=m,n<=10),表示物品数,第二行有n个数,分别表示这n件物品的数量。
输出:对应每组数据输出排列数。(任何运算不会超出2^31的范围)。
样例输入:
2 2 1 1
样例输出:
2
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
typedef long long LL;
using namespace std;
const int N = 11;
double c1[N],c2[N]; //注意类型
LL fac[N];
void cal(){
fac[0]=1; //0!会被用到
for(int i=1;i<N;i++)
fac[i]=i*fac[i-1];
}
int main(){
cal();
int n,r;
while(~scanf("%d%d",&n,&r)){
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
c1[0]=1;
int num;
for(int i=1;i<=n;i++){
scanf("%d",&num);
if(num==0) continue;
for(int j=0;j<=r;j++){
for(int k=0;k<=num&&k+j<=r;k++){
c2[k+j]+=c1[j]/fac[k];
}
}
for(int j=0;j<=r;j++){
c1[j]=c2[j];
c2[j]=0;
}
}
printf("%.0lf\n",c1[r]*fac[r]);
}
return 0;
}
关键代码:
c1[0]=1;
int num;
for(int i=1;i<=n;i++){
scanf("%d",&num);
if(num==0) continue;
for(int j=0;j<=r;j++){
for(int k=0;k<=num&&k+j<=r;k++){
c2[k+j]+=c1[j]/fac[k];
}
}
for(int j=0;j<=r;j++){
c1[j]=c2[j];
c2[j]=0;
}
}
与第一个题目是类似的。注意题目描述的差别
5、求n位十进制数中出现偶数个5的数的个数。
这道题可以使用数位dp来解决,但是也可以使用母函数的办法。
令xn表示n位十进制数中出现偶数个5的数的个数,令yn表示n为十进制数中出现奇数个5的数的个数,则有如下分析:
当n>1时:xn = 9xn-1 + yn-1且yn = 9yn-1 + xn-1,其中,x1 = 8,y1 = 1。当n>1时,x1指的是数的最高位,可以取5以外的1,2,3,4,6,7,8,9八个数中的一个,因为数的最高位没有0,所以x1不能取0。利用公式可以地推算出x2,y2,……,xn,yn。
但是,当n=1时:
xn = 9,yn = 1
6、斐波那契数列
递推公式:
f[i]=f[i-1]+f[i-2],i>=2
如果i特别大,可以考虑使用矩阵快速幂的方法进行求解。
7、斯特林数
第一类斯特林数:
有正负的,其绝对值是包含n个元素的集合分作k个环排列的方法数目。
递推公式为:
S(n,0)=0 S ( n , 0 ) = 0
S(1,1)=1 S ( 1 , 1 ) = 1
S(n+1,k)=S(n,k−1)+nS(n,k) S ( n + 1 , k ) = S ( n , k − 1 ) + n S ( n , k )
第二类斯特林数:
是把包含n个元素的集合划分为正好k个非空子集的方法的数目。
递推公式为:
S(n,k)=0(n<kork=0) S ( n , k ) = 0 ( n < k o r k = 0 )
S(n,n)=S(n,1)=1 S ( n , n ) = S ( n , 1 ) = 1
S(n,k)=S(n−1,k−1)+kS(n−1,k) S ( n , k ) = S ( n − 1 , k − 1 ) + k S ( n − 1 , k )
例题:将n个有区别的求放入k个无标号的盒子中(盒子不能为空)的方案数
8、卡特兰数
前几项为$$1、1、2、5、14、42、132……
递推关系:
h(n) = C(2n,n)/(n+1) (n=1,2,3,……)
例题1:一个栈(无穷大)的进栈序列为1,2,3,……,你,有多少个不同的出栈序列。
例题2:一堆火车以严格的顺序到一个站里,问出来的时候有多少种顺序
输入:输入包含几个例子,每个例子包含一个正整数N(N小于等于100)
输出:输出所有的火车从车站里出来有多少种顺序。
样例输入:
1
2
3
10
样例输出:
1
2
5
16796
分析:由于结果会很大,需要用大数来解决,公式为:h(n) = h(n-1)*(4*n-2)/n+1.