学校作业-Usaco DP水题
好吧,因为USACO挂掉了,所以我写的所有代码都不保证正确性【好的,这么简单的题,再不写对,你就可以滚粗了!
第一题是USACO 2.2.2
★Subset Sums 集合
对于从 1 到 N 的连续整集合合,能划分成两个子集合,且保证每个集合的数字和是相等的.
举个例子,如果 N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数字和是相等的:
{3} and {1,2} 26
这是唯一一种分发(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总数)
如果 N=7,有四种方法能划分集合{1,2,3,4,5,6,7},每一种分发的子集合各数字和是相等的:
{1,6,7} and {2,3,4,5} {注 1+6+7=2+3+4+5}
{2,5,7} and {1,3,4,6}
{3,4,7} and {1,2,5,6}
{1,2,4,7} and {3,5,6}
给出 N,你的程序应该输出划分方案总数,如果不存在这样的划分方案,则输出 0.程序不能预存结果
直接输出.
PROGRAM NAME: subset
INPUT FORMAT
输入文件只有一行,且只有一个整数 N
SAMPLE INPUT (file subset.in)
7
OUTPUT FORMAT
输出划分方案总数,如果不存在则输出 0.
SAMPLE OUTPUT (file subset.out)
4
——分割线——
这道题其实就是一个背包,就是求用1~n组合成(n+1)*n/4的方案数。我们记f[x]表示组成和为x我们的方案数,我们尝试每个数k,从(n+1)*n/4开始到k即为p寻找一旦p-k这个值可以通过1~k-1这些数组成,即f[p-k]!=0。那么,我们就使f[p]+=f[p-k],即每个可以组成p-k的方案在加上一个k就可以组成p的方案。
/*Author:WNJXYK*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std; #define LL long long inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;} const int Maxn=2000;
int n;
int Sum=0;
int f[Maxn+10]; int main(){
scanf("%d",&n);
Sum=(n+1)*n/2/2;
f[0]=1;
for (int i=n;i>=1;i--){
for (int j=Sum;j>=i;j--){
f[j]=f[j]+f[j-i];
}
}
printf("%d\n",f[Sum]/2);
return 0;
}
第二题是USACO 2.3.1
★Longest Prefix 最长前缀
在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的.生物学家对于把长的序列 28
分解成较短的(称之为元素的)序列很感兴趣.
如果一个集合 P 中的元素可以通过串联(允许重复;串联,相当于 Pascal 中的 “+” 运算符)
组成一个序列 S ,那么我们认为序列 S 可以分解为 P 中的元素.并不是所有的元素都必须出现.
举个例子,序列 ABABACABAAB 可以分解为下面集合中的元素:
{A, AB, BA, CA, BBC}
序列 S 的前面 K 个字符称作 S 中长度为 K 的前缀.设计一个程序,输入一个元素集合以及一个
大写字母序列,计算这个序列最长的前缀的长度.
PROGRAM NAME: prefix
INPUT FORMAT
输入数据的开头包括 1..200 个元素(长度为 1..10 )组成的集合,用连续的以空格分开的字符串
表示.字母全部是大写,数据可能不止一行.元素集合结束的标志是一个只包含一个 “.” 的行.集
合中的元素没有重复.接着是大写字母序列 S ,长度为 1..200,000 ,用一行或者多行的字符串来表
示,每行不超过 76 个字符.换行符并不是序列 S 的一部分.
SAMPLE INPUT (file prefix.in)
A AB BA CA BBC
ABABACABAABC
OUTPUT FORMAT
只有一行,输出一个整数,表示 S 能够分解成 P 中元素的最长前缀的长度.
SAMPLE OUTPUT (file prefix.out)
11
——分割线——
这道题我也没仔细想,脑不了个方法写出啦就好了、、就是即f[k]表示母串到第k位是否能被集合串组成,这样一旦母串从第1~p位的子串的后缀等于一集合串s,且p-s.length()的可以被组成的话,那么母串到第p为也可以被组成,即f[p]=true。
/*Author:WNJXYK*/
#include<cstdio>
#include<string>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std; #define LL long long inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;} const int Maxn=200;
string lset[Maxn+10];
int ls=0;
string str;
int lr;
bool f[2000001]; bool cmpstr(int index,int local){
for (int i=local-lset[index].length(),j=0;j<lset[index].length();i++,j++){
if (str[i]!=lset[index][j]){
return false;
}
}
return true;
} int main(){
string temp;
while(cin>>temp,temp!=".") lset[++ls]=temp;
cin>>str;lr=str.length();
f[0]=true;
for (int i=1;i<=lr;i++){
for (int j=1;j<=ls;j++){
if (lset[j].length()>i) continue;
if (f[i-lset[j].length()] && cmpstr(j,i)){
f[i]=true;
break;
}
}
}
int ans=lr;
for (;ans>=1;ans--) if (f[ans])break;
printf("%d\n",ans);
return 0;
}
第三题是USACO 2.3.4
★Money Systems 货币系统
母牛们不但创建了他们自己的政府而且选择了建立了自己的货币系统.
[In their own rebellious way],,他们对货币的数值感到好奇.
传统地,一个货币系统是由 1,5,10,20 或 25,50, 和 100 的单位面值组成的.
母牛想知道有多少种不同的方法来用货币系统中的货币来构造一个确定的数值.
举例来说, 使用一个货币系统 {1,2,5,10,...}产生 18 单位面值的一些可能的方法是:18x1, 9x2,
8x2+2x1, 3x5+2+1,等等其它.
写一个程序来计算有多少种方法用给定的货币系统来构造一定数量的面值.
保证总数将会适合 long long (C/C++) 和 Int64 (Free Pascal).
PROGRAM NAME: money
INPUT FORMAT
货币系统中货币的种类数目是 V . (1<= V<=25)
要构造的数量钱是 N . (1<= N<=10,000)
第 1 行: 二整数, V 和 N
第 2 ..V+1 行: 可用的货币 V 个整数 (每行一个 每行没有其它的数).
SAMPLE INPUT (file money.in)
3 10
1 2 5
OUTPUT FORMAT
单独的一行包含那个可能的构造的方案数.
SAMPLE OUTPUT (file money.out)
10
——分割线——
这一题和第一题实际上是一样的,只不过这次每个元素可以重复使用,即无限背包。状态也是f[k]表示组成k的方案数,转移和第一题一样,唯一的区别是这次我们转移要从面值小的到面值大的转移,这样可以保证每个元素可以被多次使用。
代码:
/*Author:WNJXYK*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std; #define LL long long inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;} const int Maxm=10000;
const int Maxn=25;
int V[Maxn+10];
int N;
int n;
LL f[Maxm+10]; int main(){
scanf("%d%d",&n,&N);
for (int i=1;i<=n;i++) scanf("%I64d",&V[i]);
f[0]=1;
for (int i=1;i<=n;i++){
for (int j=V[i];j<=N;j++){
f[j]+=f[j-V[i]];
}
}
printf("%I64d",f[N]);
return 0;
}
第四题是USACO 3.1.2
★Score Inflation 总分
学生在我们 USACO 的竞赛中的得分越多我们越高兴.我们试着设计我们的竞赛以便人们能尽可能的
多得分,这需要你的帮助.我们可以从几个种类中选取竞赛的题目,这里的一个"种类"是指一个竞赛
题目的集合,解决集合中的题目需要相同多的时间并且能得到相同的分数.
你的任务是写一个程序来告诉 USACO 的职员,应该从每一个种类中选取多少题目,使得解决题目的
总耗时在竞赛规定的时间里并且总分最大.
输入包括竞赛的时间,M(1 <= M <= 10,000)(不要担心,你要到了训练营中才会有长时间的比赛)和
N,"种类"的数目 1 <= N <= 10,000.
后面的每一行将包括两个整数来描述一个"种类":
第一个整数说明解决这种题目能得的分数(1 <= points <= 10000),第二整数说明解决这种题目所
需的时间(1 <= minutes <= 10000).
你的程序应该确定我们应该从每个"种类"中选多少道题目使得能在竞赛的时间中得到最大的分数.
来自任意的"种类"的题目数目可能任何非负数(0 或更多).计算可能得到的最大分数.
PROGRAM NAME: inflate
INPUT FORMAT
第 1 行: M, N--竞赛的时间和题目"种类"的数目.
第 2-N+1 行: 两个整数:每个"种类"题目的分数和耗时.
SAMPLE INPUT (file inflate.in)
300 4
100 60
250 120
120 100
35 20
OUTPUT FORMAT
单独的一行包括那个在给定的限制里可能得到的最大的分数.
SAMPLE OUTPUT (file inflate.out)
605
{从第 2 个"种类"中选两题第 4 个"种类"中选三题}
——分割线——
好吧,这道题就是一个无限背包,和上题是一样的,只不过这次F[k]表示的是用k的时间能达到的最大收益。F[j]=max(F[j],F[j-T[i]]+V[i]),因为是无限背包所以从小时间到大时间依次转移就好了。P.S.深受学校毒害,我还以为竞赛只能每门弄一次呢!竟然Wa了一次样例QAQ
代码:
/*Author:WNJXYK*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std; #define LL long long inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;} const int Maxn=10000;
const int Maxm=10000;
int T[Maxn+10];
int V[Maxn+10];
int F[Maxm+10];
int n,m; int main(){
scanf("%d%d",&m,&n);
for (int i=1;i<=n;i++) scanf("%d%d",&V[i],&T[i]);
for (int i=1;i<=n;i++){
for (int j=T[i];j<=m;j++){
F[j]=remax(F[j],F[j-T[i]]+V[i]);
}
}
int Ans=0;
for (int i=1;i<=m;i++) Ans=remax(Ans,F[i]);
printf("%d\n",Ans);
return 0;
}
第五题是USACO 3.1.6
★Stamps 邮票
已知一个 N 枚邮票的面值集合(如,{1 分,3 分})和一个上限 K —— 表示信封上能够贴 K 张邮
票.计算从 1 到 M 的最大连续可贴出的邮资.
例如,假设有 1 分和 3 分的邮票;你最多可以贴 5 张邮票.很容易贴出 1 到 5 分的邮资(用 1
分邮票贴就行了),接下来的邮资也不难:
6 = 3 + 3
7 = 3 + 3 + 1
8 = 3 + 3 + 1 + 1
9 = 3 + 3 + 3
10 = 3 + 3 + 3 + 1
11 = 3 + 3 + 3 + 1 + 1
12 = 3 + 3 + 3 + 3
13 = 3 + 3 + 3 + 3 + 1.
然而,使用 5 枚 1 分或者 3 分的邮票根本不可能贴出 14 分的邮资.因此,对于这两种邮票的集
合和上限 K=5,答案是 M=13.
PROGRAM NAME: stamps
INPUT FORMAT
第 1 行: 两个整数,K 和 N.K(1 <= K <= 200)是可用的邮票总数.N(1 <= N <= 50)是邮票面
值的数量.
第 2 行 .. 文件末: N 个整数,每行 15 个,列出所有的 N 个邮票的面值,面值不超过 10000.
SAMPLE INPUT (file stamps.in)
5 2
1 3
OUTPUT FORMAT
第 1 行: 一个整数,从 1 分开始连续的可用集合中不多于 K 张邮票贴出的邮资数.
SAMPLE OUTPUT (file stamps.out)
13
——分割线——
好吧,这道题目本质上和上面的题目是一样的,只不过要注意分层的问题,就是邮票使用的数量每次都要控制,这样DP要多出一维来记录使用邮票数f[k][m]表示k张邮票是否能组成m面值。f[k][m]=所有f[k-1][m-V[i]]的或值【i属于n】滚动数组可优化!
代码:
/*Author:WNJXYK*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std; #define LL long long inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;} const int Maxm=500000;
const int Maxn=50;
int v[Maxn+10];
int n,k;
int maxm=0;
bool f[205][Maxm+10]; int main(){
scanf("%d%d",&k,&n);
for (int i=1;i<=n;i++) scanf("%d",&v[i]);
memset(f,false,sizeof(f));
for (int i=1;i<=n;i++) {f[1][v[i]]=true;maxm=remax(maxm,v[i]);}
for (int RunTimes=2;RunTimes<=k;RunTimes++){
for (int i=1;i<=n;i++){
for (int j=maxm;j>=0;j--){
if (f[RunTimes-1][j]&&!f[RunTimes][j+v[i]]){
f[RunTimes][j+v[i]]=true;
maxm=remax(maxm,j+v[i]);
}
}
}
}
int Ans=1;
for (;;Ans++){
bool flag=false;
for (int i=1;i<=k;i++) if (f[i][Ans]){flag=true;break;}
if (!flag) break;
}
printf("%Id\n",Ans-1);
return 0;
}
第五题是USACO 5.1.3
★Musical Themes 乐曲主题
我们用 N(1 <= N <=5000)个音符的序列来表示一首乐曲,每个音符都是 1..88 范围内的整数,每个
数表示钢琴上的一个键.很不幸这种表示旋律的方法忽略了音符的时值,但这项编程任务是关于音
高的,与时值无关.
许多作曲家围绕一个重复出现的“主题”来构建乐曲.在我们的乐曲表示法中,“主题”是整个音
符序列的一个子序列,它需要满足如下条件:
长度至少为 5 个音符
在乐曲中重复出现(可能经过转调,见下)
重复出现的同一主题不能重叠
“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值.
给定一段乐曲,计算其中最长主题的长度(即音符数).
本题时限为 1 秒钟!
PROGRAM NAME: theme
INPUT FORMAT
输出文件的第一行包含整数 N.下面的每一行(最后一行可能除外)包含 20 个整数,表示音符序列.最
后一行可能少于 20 个音符.
SAMPLE INPUT (file theme.in)
30
25 27 30 34 39 45 52 60 69 79 69 60 52 45 39 34 30 26 22 18
82 78 74 70 66 67 64 60 65 80
OUTPUT FORMAT
输出文件应只含一个整数,即最长主题的长度.如果乐曲中没有主题,那么输出 0.
SAMPLE OUTPUT (file theme.out)
5
(这个长度为 5 的主题是输入文件中第一行的最后 5 个音符和第二行开头 5 个音符)
——分割线——
F[I][J]为第I个与第J个匹配时的最大值
方程:F[I][J]=MAX(F[I][J],F[I-1][J-1]+1) (A[I]-A[J]==A[I-1]-A[J-1])
答案就是所有F[I][J]的最大值,最大值在求的时候顺便算出就行了。滚动数组可优化。
代码:
/*Author:WNJXYK*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std; #define LL long long inline void swap(int &x,int &y){int tmp=x;x=y;y=tmp;}
inline void swap(LL &x,LL &y){LL tmp=x;x=y;y=tmp;}
inline int remin(int a,int b){if (a<b) return a;return b;}
inline int remax(int a,int b){if (a>b) return a;return b;}
inline LL remin(LL a,LL b){if (a<b) return a;return b;}
inline LL remax(LL a,LL b){if (a>b) return a;return b;} const int Maxn=50003;
int n=0,a[Maxn],l;
int f[Maxn],f1[Maxn],ans=0; int main(){
scanf("%d",&n);
l=n/2;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);a[0]=0x7FFFFFFF;
for(int i=1;i<=n;i++){
for(int j=1;j<=i-1;j++)
if(a[i]-a[j]==a[i-1]-a[j-1]&&i-f1[j-1]-1>j){
f[j]=remax(f[j],f1[j-1]+1);
ans=remax(ans,f[j]);
}
memcpy(f1,f,sizeof f1);
memset(f,0,sizeof f);
}
if(ans+1>=5)
printf("%d\n",ans+1);
else
printf("0\n");
return 0;
}
QAQ收工睡觉!
学校作业-Usaco DP水题的更多相关文章
- ACM :漫漫上学路 -DP -水题
CSU 1772 漫漫上学路 Time Limit: 1000MS Memory Limit: 131072KB 64bit IO Format: %lld & %llu Submit ...
- [poj2247] Humble Numbers (DP水题)
DP 水题 Description A number whose only prime factors are 2,3,5 or 7 is called a humble number. The se ...
- Codeforces 148D 一袋老鼠 Bag of mice | 概率DP 水题
除非特别忙,我接下来会尽可能翻译我做的每道CF题的题面! Codeforces 148D 一袋老鼠 Bag of mice | 概率DP 水题 题面 胡小兔和司公子都认为对方是垃圾. 为了决出谁才是垃 ...
- 13年山东省赛 The number of steps(概率dp水题)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud The number of steps Time Limit: 1 Sec Me ...
- dp水题 序列问题 (9道)
9道题.A了8道,A题看题解也没弄懂怎么维护m段子序列的,过一段时间再回来看看 dp试水 47:56:23 125:00:00 Overview Problem Status Rank ( ...
- 【BZOJ】1270: [BeijingWc2008]雷涛的小猫(DP+水题)
http://www.lydsy.com/JudgeOnline/problem.php?id=1270 这完全是一眼题啊,但是n^2的时间挺感人.(n^2一下的级别请大神们赐教,我还没学多少dp优化 ...
- 【DP水题】投票问题(二)
投票问题(一) [试题描述] 欧阳文和欧阳武竞选学联主席,汪梁森负责唱票,共有m+n张,结果欧阳文获胜,已知欧阳文和欧阳武分别获得 m 张票和 n 张票(m>n).现在请你计算在唱票过程中欧阳文 ...
- POJ 3254 - Corn Fields - [状压DP水题]
题目链接:http://poj.org/problem?id=3254 Time Limit: 2000MS Memory Limit: 65536K Description Farmer John ...
- openjudge dp水题记录
当发现自己竟然不会打dp的时候内心是崩溃的,然后按照一年前的刷题记录刷openjudge,然后发现自己准确率比一年前(刚学信竞两个月时)的准确率低得多,已经没救. 列一下最近打的几道sb题 2985: ...
随机推荐
- Android应用开发基础篇(3)-----ListView
一.概述 ListView是一个列表显示控件,它的应用非常广泛,在很多应用程序中都可以看到它的身影,比如来电通,网易新闻等等,特别是QQ.因此非常有必要熟练掌握它. 二.要求 能够利用ListView ...
- os基础
命令:指计算机用户要求计算机系统为其工作的指示: 命令的表示形式: 1.字符形式: 2.菜单形式: 3.图形形式: 命令的使用方式:1. 脱机使用方式 off_line 2.联机使用方式 ...
- 在Mac pro上如何配置adb命令?
在Mac pro上如何将Android SDK的adb命令添加到环境变量中,这里将进行说明! 方法/步骤 1 启动终端,可以在Spotlight中搜索“终端” 2 进入当前用户的HOME目录,命令如下 ...
- Immediate Decodability问题Java解答
DescriptionAn encoding of a set of symbols is said to be immediately decodable if no code for one sy ...
- [一个经典的多线程同步问题]解决方案一:关键段CS
前面提出了一个经典的多线程同步互斥问题,本篇将用关键段CRITICAL_SECTION来尝试解决这个问题. 本文先介绍如何使用关键段,然后再深层次的分析下关键段的实现机制和原理. 关键段CRITICA ...
- Linux 下 Hadoop java api 问题
1. org.apache.hadoop.security.AccessControlException: Permission denied: user=opsuser, access=WRITE, ...
- JVM典型配置
堆大小设置: JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存 限制.32位系统下,一般限制在1.5G~2G:64为 ...
- MVC-03 控制器(2)
五.ActionResult解说 ActionResult的继承图: 类型 Controller辅助方法 用途帮助 ContentResult Content 回传一个用户自定义的文字属性 Empty ...
- 全新的ASP.NET !
全新的ASP.NET ! 背景 最新版本的 ASP.NET 叫做 ASP.NET Core (也被称为 ASP.NET 5) 它颠覆了过去的 ASP.NET. 什么是 ASP.NET Core? ...
- Jacob
http://www.cnblogs.com/luckyxiaoxuan/archive/2012/06/13/2548331.html http://blog.csdn.net/qingwangyo ...