6.8 模拟赛记录
这回的题还是很有意思的。
T1一般的背包,切了。
T2首先能看出来是一个类似多重背包的东西:花钱买魔法书,不同等级价值不同,花费倍增。一种书的不同等级只能买一本,求最大价值。
一开始先考虑能不能合成01,认为可以,于是写完了。写完了才品出来不大对劲,合成不了,于是把合成拆了;拆完发现还是不行,就得正常写多重的思路,而且挂不了二进制优化。
结果多重的模版不熟悉(学会二进制优化简单的就不会了,怀念同样命运的递推n2LIS和冒泡排序),两维写反了,发现之后一时间居然不知道怎么改(?),于是浪费了一些时间。
还是得注意,这题方案同样优秀时输出字典序小的,所以原则是能不更新就不更新。被卡了9分。
方案输出永远是一个话题。为了防止重复,pre数组多约束一个花费。毕竟如果同样多的书花了同样多的钱,判断足以保护字典序,不可能出现方案的交叉。最后递归输出就可以了。
求各位出数据和题干的dalao,没有spj好歹字典序给个约束也行啊…要不是被坑出经验了根本debug不出来这个问题。(血压飙升)
附个核心代码:
for(i = 1;i <= n;i++){
for(k = m;k >= 0;k--){
for(j = 1;j <= p[i];j++){
if(k - w[i][j] >= 0){
if(dp[k - w[i][j]] + c[i][j] > dp[k]){
pre[i][k] = j;
dp[k] = dp[k - w[i][j]] + c[i][j];
}
}
}
}
}
T3这题题干我真的无法概括。
首先,注意到每走一个格花费一点体力和时间,所以这俩完全能整合成一个。但是要特别注意,这地方体力不能为0(放中间真的恶心人,卡掉我50分),故而需要把体力-1之后取最小。
接着看,每摘一次走2*(x + y),所以可以当多重背包做。
然后二进制优化,但是这地方特别坑爹的地方在于,不见得一个点有桃子就一定能摘,反之亦然。说白了有可能出现一个点0个桃子摘n次或者几个桃子摘0次,所以不能一步到位(上来先存价值,然后cnt清零存次数,使得次数与价值对应),否则会错位。这个题干完全不体现,我觉得不太合理。以及,我又被自己写的二进制优化卡了…(捂脸)
总之这题难点是审题。
完整代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long f[101][101],g[101][101],dp[140001],w[10001],c[10001],b[10001],w1[140001],c1[140001];
int main(){
int m,n,i,j,k;
long long x,y,z,cnt = 0,temp = 0;
scanf("%lld %lld %d %d",&x,&y,&m,&n);
n--;
m = min(m,n);
for(i = 1;i <= x;i++){
for(j = 1;j <= y;j++){
scanf("%lld",&f[i][j]);
}
}
for(i = 1;i <= x;i++){
for(j = 1;j <= y;j++){
scanf("%lld",&g[i][j]);
if(f[i][j]){
w[++temp] = 2 * (i + j);
c[temp] = f[i][j];
b[temp] = g[i][j];
}
}
}
for(i = 1;i <= temp;i++){
for(j = 0;(1 << j) <= b[i];j++){
w1[++cnt] = w[i] * (1 << j);
c1[cnt] = c[i] * (1 << j);
b[i] -= (1 << j);
}
if(b[i]){
w1[++cnt] = w[i] * b[i];
c1[cnt] = c[i] * b[i];
}
}
//for(i = 1;i <= cnt;i++) printf("%lld %lld\n",w1[i],c1[i]);
for(i = 1;i <= cnt;i++){
for(j = m;j >= w1[i];j--){
dp[j] = max(dp[j],dp[j - w1[i]] + c1[i]);
}
}
printf("%lld\n",dp[m]);
return 0;
}
T4,已知附件个数,且非常少,所以大可以分类讨论,不然要树形DP。
注意这地方对应主件序号是原序列的序号而非主件序号,存的时候要万分注意。
for(i = 1;i <= n;i++){
scanf("%lld %lld %lld",&x,&y,&op[i]);
z = op[i];
if(!z){
c[i][0] = x * y,w[i][0] = x;
}
else{
if(!c[z][1]) c[z][1] = x * y,w[z][1] = x;
else c[z][2] = x * y,w[z][2] = x;
}
}
for(i = 1;i <= n;i++){
if(op[i]) continue;
for(j = m;j >= w[i][0];j--){
dp[j] = max(dp[j],dp[j - w[i][0]] + c[i][0]);
if(w[i][1] && j - w[i][0] - w[i][1] >= 0) dp[j] = max(dp[j],dp[j - w[i][0] - w[i][1]] + c[i][0] + c[i][1]);
if(w[i][2] && j - w[i][0] - w[i][2] >= 0) dp[j] = max(dp[j],dp[j - w[i][0] - w[i][2]] + c[i][0] + c[i][2]);
if(w[i][1] && w[i][2] && j - w[i][0] - w[i][1] - w[i][2] >= 0) dp[j] = max(dp[j],dp[j - w[i][0] - w[i][1] - w[i][2]] + c[i][0] + c[i][1] + c[i][2]);
}
}
总之考的还行,T2卡的非常尴尬,T3审题纯粹考心态。结合上次的经验,永远不要奢望能一个半小时AK,否则只会被AK。(捂脸)