由于此题是CSP-J考场上的一道题,我们不妨先假设自己是一名菜鸟考生,用一些比较新鲜的角度去做题。
正文
考试时会先干嘛呢?那一定是去看数据范围。CSP比GESP好的点就在于它不会让你输得太难看,总有几分是你水得到的。显然这里有10%的数据是很轻松就能做对的,就是当T=1(即小伟的神力有但完全没用,只能预测一天)时,他买纪念品却不能以更高的价格卖出,因为当天的价格是不变的,类似于炒股,所以他最后所持有的金币数与他最开始拥有的金币数是一样的。这里就先不给代码了。相信大家都是比我厉害的大佬
当然只水十分不太对得起我们辛苦的思考,考虑到T<=100,N=1时有15%的数据,意思是超能力持续天数变多但是只有一种商品,所以操作就是如果明天价格更贵,就用今天的钱买尽量多的纪念品,第二天再卖掉,所以第二天后手里有的金币数就该是今天能买到的*明天价格+今天余数,对应的代码如下:
intans=m;for(inti=0;i<t;i++){if(p[i+1][0]>p[i][0]){intcnt=ans/p[i][0];ans=ans%p[i][0]+cnt*p[i+1][0];}}cout<<ans;进一步地,我们还能看到有15%的数据是T=2,也就是超能力持续两天,刚好够做一次交易。这时我们先来捋一捋思路:小伟手中金币数一定,也就是只能选择部分纪念品进行买卖,每种纪念品可以购买无数次(钱够),最后使得第二天卖出时利益最大,不难看出这是一个简单的完全背包问题,手里钱数是背包容量,今天的价格对应物品体积,明天价格则是物品价值,然后直接套完全背包模板就可以了。(如果第二天价格比今天还便宜,直接continue掉)
实际上这里做出来后,就很接近最后的AC代码了,因为取的是特殊值两天,我们就可以尝试把这T天分成两天一次的背包,即今天和明天,明天和后天…以此类推,要进行T-1次,不过每天都要更新手里的金币数。
完整代码:
#include<bits/stdc++.h>usingnamespacestd;intn,m,t;intp[105][105];voidcheck1(){intans=m;for(inti=0;i<t;i++){if(p[i+1][0]>p[i][0]){intcnt=ans/p[i][0];ans=ans%p[i][0]+cnt*p[i+1][0];}}cout<<ans;}voidcheck2(){intdp[1000005];memset(dp,0,sizeof(dp));for(inti=0;i<n;i++){intcost=p[0][i];intv=p[1][i]-cost;if(v<=0){continue;}for(intj=cost;j<=m;j++){dp[j]=max(dp[j],dp[j-cost]+v);}}cout<<m+dp[m];}voidcheck3(){intdp[100005];for(intd=0;d<t-1;d++){memset(dp,0,sizeof(dp));for(inti=0;i<n;i++){intcost=p[d][i];intv=p[d+1][i]-cost;if(v<=0){continue;}for(intj=cost;j<=m;j++){dp[j]=max(dp[j],dp[j-cost]+v);}}m+=dp[m];}cout<<m;}intmain(){cin>>t>>n>>m;for(inti=0;i<t;i++){for(intj=0;j<n;j++){cin>>p[i][j];}}if(t==1){cout<<m;return0;}if(n==1){check1();return0;}if(t==2){check2();return0;}//以上是前面的骗分环节,只保留check3也行check3();return0;}注:老师作业要求,不喜勿喷