个人认为,今天的考题要比昨天的难许多,其实尽可能做完可做的题后,并没有抱有拿高分的希望。虽然几题样例过了,心里还是有些悬的。
鉴于昨天得到的教训,我放弃手打文件输入输出,改用复制粘贴,之后在交前复查,确保了万无一失。然而,我亲爱的同桌继承了我的优良传统,也少打了一个"r",100分很正的正解就飞了,最后排名垫了底。
可见,God一直在强调细节的重要性。
一点开题目“奶牛”和“Farmer John”就映入眼帘,USACO的题啊~一般似乎都不是很水。
照理来说,第一题是比较简单的,看完题目后,根据印象与直觉,认为是第一题比较好理解,应该会有比较清晰的思路。开始下手。
T1 接苹果
题目大意:
奶牛喜欢吃苹果。约翰有两棵苹果树,有 N 只苹果会从树上陆续落下。如果掉苹果的时候,贝西在那棵树下,她就能接住苹果。贝西一开始在第一棵树下。在苹果掉落之前,她有足够的时间来回走动,但她很懒,最多只愿意移动 K 次。请计算一下她最多可以接住几只苹果。
(因为各种原因,选择截个图)
看完题,先划重点:两棵树,最多走k次(可以走<k次)等
照常的我先开始去理解样例,然后形象地画个图。因为是DP专题考试,因此很容易地,我就往那方面想,在白白净净的草稿纸上列方程,乱七八糟地绘一通。过程中,我搞不清三维的怎么做(很奇怪),拼命地推二维,对于这些深奥的问题我都不能写在纸上表达出来,在脑子里想象然后有点被绕懵,过了很久才理清楚。之后我就根据推出的不太靠谱的状态转移方程码了代码,肯定不能一帆风顺,添了许多小语句修bug,成了这副模样:
很莫名的评测出来是唯一一个90分,最后一个点小1。
正解:
#include<bits/stdc++.h>
using namespace std;
int n,k;
int maxx=-1010101010;
int a[5555],b[5555];
int f[5555][55];//表示奶牛在第i分钟内转移了j次能够接到的最多苹果
int main()
{
freopen("bcatch.in","r",stdin);
freopen("bcatch.out","w",stdout);
cin>>n>>k;
int cnt=1;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
for(int j=0;j<=min(k,n);j++)
{
if(j==0)
f[i][j]=f[i-1][j];
else
f[i][j]=max(f[i-1][j],f[i-1][j-1]);
if(a[i]==j%2+1) f[i][j]++;//确定苹果从当前站的树上掉下来
}
for(int i=1;i<=k;i++)
maxx=max(maxx,f[n][i]);
cout<<maxx<<endl;
return 0;
}
T2 奶牛飞盘队
题目大意:
农夫顿因开始玩飞盘之后,约翰也打算让奶牛们享受飞盘的乐趣.他要组建一只奶牛飞盘队.
他的N(1≤N≤2000)只奶牛,每只部有一个飞盘水准指数Ri(1≤Ri≤100000).约翰要选出1只或多于1只奶牛来参加他的飞盘队.
约翰比较迷信,他的幸运数字是F,所以他要求队伍的总能力必须是F的倍数。请帮他算一下,符合这个要求的队伍组合有多少?由于这个数字很大,只要输出答案除以10^8 的余数就可以了。
对于第二题,第一反应:暴力枚举??
但是搞来搞去,发现实际上我帮不会实现,最后实在是不行了,直接输了个样例。丢弃。
那么,之后老师讲正解的时候……0/1背包??我的天。
他是这么说的:“第i只牛有两种可能性,要还是不要,所以,这个我们可以往0/1背包上考虑。
因为我们要求的是F的整数倍的方案数,我们只考虑这种可能性显然无法满足最优子结构,按照我们常见的套路,我们显然要把 当前组成的累加和 对 F mod 的值进行存储。”
之后显然
#include<bits/stdc++.h>
using namespace std;
int n,F;
int f[2000][2000];//选到第i件物品是,%mod后余数为j的方案数
int r[1555];
int const mod=1e8;
int main()
{
freopen("fristeam.in","r",stdin);
freopen("fristeam.out","w",stdout);
// cin>>n>>F;
scanf("%d%d",&n,&F);
for(int i=1;i<=n;i++)
cin>>r[i],f[i][r[i]%F]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<F;j++)
f[i][j]=(f[i][j]+f[i-1][j]+f[i-1][((j-r[i])%F+F)%F])%mod;//选和不选都算
// cout<<f[n][0]<<endl;
printf("%d\n",f[n][0]);
return 0;
}
我觉得这主要还是对于%的操作,我们部分人还是不太清楚的
T4 248
题目大意:
给定一个1*N(2<=N<=248) 的地图,在里面玩2048,每次可以合并相邻两个(数值范围1-40),问最大能合出多少。注意合并后的数值并非加倍而是+1,例如2与2合并后的数值为3。
看完题目,立马与“石子合并”重合在一起,套了个区间DP模板上去,谁知还过了,非常有成就感。
题目中有一点要注意:合并之前有个条件,这两个要合并的区间的值要一样。
对于一些题目,脑海中要有画面,他可能会唤起一些曾经的记忆,感到熟悉了,心里就有了底,有了方向,那么,我认为,做题的时候就比较顺利且正确率会高一些
#include<bits/stdc++.h>
using namespace std;
int n;
int maxx=-101010101;
int ll,rr;
int a[300];
int f[300][300];
int main()
{
freopen("248.in","r",stdin);
freopen("248.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i],maxx=max(maxx,a[i]);
for(int i=1;i<=n;i++)
f[i][i]=a[i];
for(int len=2;len<=n;len++)//以长度为阶段
for(int l=1;l<=n;l++)//左端点状态
{
int r=l+len-1;//右端点状态
if(r<=n)
{
for(int k=l;k<r;k++)
if(f[l][k]==f[k+1][r]&&f[l][k]+1>f[l][r])
f[l][r]=f[l][k]+1;
// cout<<l<<' '<<r<<' '<<f[l][r]<<endl;
if(maxx<f[l][r])
{
maxx=f[l][r];
ll=l,rr=r;
}
}
}
cout<<maxx<<endl;
// cout<<ll<<' '<<rr<<endl;
return 0;
}
T3 股票市场
题目大意:
对于这道题,所有人中最高分也就14。看完题后毫无思绪,更是被股票有多种难住了。没有去碰它。
之后老师说这是完全背包,看起来是有那么点像。
(版权出自老刘)很尴尬的是T3全是截图,毕竟这道题是比较难,而且我也是看题解做出来的,老师写的也比较直观,好理解。
#include<bits/stdc++.h>
using namespace std;//股票就是物品,花费就是前一天的价格,收益就是后一天的价格,背包就是资金。
int s,d,m;
int a[100][100];
int f[510000];//表示前i个股票使用资金j能获得的最大收益
int main()
{
freopen("stock.in","r",stdin);
freopen("stock.out","w",stdout);
// cin>>s>>d>>m;
scanf("%d%d%d",&s,&d,&m);
for(int i=1;i<=s;i++)
for(int j=1;j<=d;j++)
// cin>>a[i][j];
scanf("%d",&a[i][j]);
for(int i=2;i<=d;i++)
{
int maxx=0;
memset(f,0,sizeof(f));
for(int j=1;j<=s;j++)
for(int k=a[j][i-1];k<=m;k++)
{
f[k]=max(f[k],f[k-a[j][i-1]]+a[j][i]-a[j][i-1]);
maxx=max(maxx,f[k]);
}
m+=maxx;
}
// cout<<m<<endl;
printf("%d\n",m);
return 0;
}
对于T5我能力不足无法写出,这题与T4除了数据范围其他一模一样,T4代码交上去会有20分。
对于今天的考试,我该拿得分都拿到了,rating也加回来不少。昨天的考试着实是个遗憾。