好吧,因为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) 

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 个音符)

——分割线——

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水题的更多相关文章

  1. ACM :漫漫上学路 -DP -水题

    CSU 1772 漫漫上学路 Time Limit: 1000MS   Memory Limit: 131072KB   64bit IO Format: %lld & %llu Submit ...

  2. [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 ...

  3. Codeforces 148D 一袋老鼠 Bag of mice | 概率DP 水题

    除非特别忙,我接下来会尽可能翻译我做的每道CF题的题面! Codeforces 148D 一袋老鼠 Bag of mice | 概率DP 水题 题面 胡小兔和司公子都认为对方是垃圾. 为了决出谁才是垃 ...

  4. 13年山东省赛 The number of steps(概率dp水题)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud The number of steps Time Limit: 1 Sec  Me ...

  5. dp水题 序列问题 (9道)

    9道题.A了8道,A题看题解也没弄懂怎么维护m段子序列的,过一段时间再回来看看     dp试水 47:56:23 125:00:00   Overview Problem Status Rank ( ...

  6. 【BZOJ】1270: [BeijingWc2008]雷涛的小猫(DP+水题)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1270 这完全是一眼题啊,但是n^2的时间挺感人.(n^2一下的级别请大神们赐教,我还没学多少dp优化 ...

  7. 【DP水题】投票问题(二)

    投票问题(一) [试题描述] 欧阳文和欧阳武竞选学联主席,汪梁森负责唱票,共有m+n张,结果欧阳文获胜,已知欧阳文和欧阳武分别获得 m 张票和 n 张票(m>n).现在请你计算在唱票过程中欧阳文 ...

  8. POJ 3254 - Corn Fields - [状压DP水题]

    题目链接:http://poj.org/problem?id=3254 Time Limit: 2000MS Memory Limit: 65536K Description Farmer John ...

  9. openjudge dp水题记录

    当发现自己竟然不会打dp的时候内心是崩溃的,然后按照一年前的刷题记录刷openjudge,然后发现自己准确率比一年前(刚学信竞两个月时)的准确率低得多,已经没救. 列一下最近打的几道sb题 2985: ...

随机推荐

  1. SQL Server 2008 错误 233 的解决办法

    问题一.忘记了登录Microsoft SQL Server 2008 的sa的登录密码 解决方法:先用windows身份验证的方式登录进去,然后在‘安全性’-‘登录’-右键单击‘sa’-‘属性’,修改 ...

  2. javascript操作JSON字符

    1.先要区分JSON字符串和JSON对象 JSON字符串: Var strJSON = “{“Area”:[{“AreaId”:”123”},{“AreaId”:”345”}]}”,   或者 Var ...

  3. CSS3新动画效果

    CSS3添加了几个动画效果的属性,通过设置这些属性,可以做出一些简单的动画效果而不需要再去借助JavaScript.CSS3动画的属性主要分为三类:transform.transition以及anim ...

  4. iOS 中多线程的简单使用

    iOS中常用的多线程操作有( NSThread, NSOperation GCD ) 为了能更直观的展现多线程操作在SB中做如下的界面布局: 当点击下载的时候从网络上下载图片: - (void)loa ...

  5. VS2015+MySql EF的配置问题

    自己做笔记,防止以后各种找! 去MySql下载最新版的安装包,MySql For Windows全部就可以了,根据开发需求安装功能,然后安装MySql的步骤上网去找一大堆. 注意事项: 第一:必须把V ...

  6. 5.4 RegExp类型

    ECMAScript通过RegExp类型来支持正则表达式.使用下面类似Perl的语法,就可以创建一个正则表达式. var expression=/pattern/flags; 复制代码 其中的模式(p ...

  7. elasticsearch-5.0.0初见

    基础概念 Elasticsearch有几个核心概念.从一开始理解这些概念会对整个学习过程有莫大的帮助. 接近实时(NRT) Elasticsearch是一个接近实时的搜索平台.这意味着,从索引一个文档 ...

  8. 1TB到底能存放多少东西?

    网盘大战逐渐升级,360和百度网盘先后推出的1TB网盘存储,而腾讯甚至为其微云网盘打出10TB的招牌来哄抢用户. 这里我们聊聊1TB的网盘究竟能放多少东西? 以下是我在网上找到的一些资料. 一)30年 ...

  9. 使用 RMI + ZooKeeper 实现远程调用框架

    目录[-] 1 发布 RMI 服务1.1 定义一个 RMI 接口1.2 编写 RMI 接口的实现类1.3 通过 JNDI 发布 RMI 服务2 调用 RMI 服务3 RMI 服务的局限性4 使用 Zo ...

  10. c++ bitset使用

    A bitset is a special container class that is designed to store bits (elements with only two possibl ...