题目
t(t<=10000)组样例,
给定n(n<=1e3)天,有三种技能,三种技能的熟练度初始都为0,
第i天学第j种技能时,会令第j种技能的熟练度提高aij(0<=aij<=1e4)
第i天只能学一种技能,剩下两种技能没有学,
对于没有学的技能k,假设算上第i天后已经是连续第x天没有学技能k了,
则第k种技能的熟练度会减少x,熟练度下降的过程中,不会小于0
求n天之后,三种技能的熟练度之和的最大值
思路来源
官方题解
题解
首先,用根号的思想,每根号w天不学,就会下降超过一天学的收益,不如期间用一天学一下
然后,用dp的松弛思想,即,合理地改变规则,使得最优解还能被枚举到
最优解中,一个课程要么没学,要么学了之后,中间不会降到0以下
而降到0以下是不会影响到最优解的转移的,所以直接扣除即可
但是,其实最优解可能只学了一门或两门课程,所以状态中还需要标明一门课学没学
在代码实现中,dp[i][j][k][l]表示到了第i天时,第i天当天学的是第j门课,
对于没学的两门课来说,第一门课已经没学k天,第二门课已经没学l天时,最大的熟练度之和
特别地,当k=0、l=0时,代表这门课从来没有学过,一直为0,转移的时候不扣除天数
滚动掉第一维后,就只剩dp[2][3][205][205]了
预处理了一下,id[i][0]表示学课程i时没学的第一门课的标号,id[i][1]表示第二门课的标号
如果当天学的j,没学的第一门课连续没学k天,没学的第二门课连续没学l天,状态dp[cur][j][k][l]
转移时,枚举下一天学的是m,需要判断一下与m对应的没学的第一/二门课连续没学的天数
int vf=(nf==j?1:(nf==f?k+(k>0):l+(l>0)));
写成if else可能会比较好理解,即,
1. 如果第一门课是j的话,当前连续没学一天,
2. 是之前没学的第一门课,
①如果这门课没学过,即k=0,就还是k=0
②否则,连续没学k+1天
3. 是之前没学的第二门课,
①如果这门课没学过,即l=0,就还是l=0
②否则,连续没学l+1天
用最后一天的结果,更新答案取最大即可
代码
#include<bits/stdc++.h>
//#include<iostream>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pb push_back
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=1e3+10,M=200,W=205,mod=998244353;
int t,n,a[N][3],dp[2][3][W][W],id[3][2];
void upd(int &x,int y){
x=max(x,y);
}
int main(){
//freopen("jinan.in","r",stdin);
//freopen("jinan.out","w",stdout);
rep(j,0,2){
int c=0;
rep(k,0,2){
if(j==k)continue;
id[j][c++]=k;
}
}
sci(t);
while(t--){
sci(n);
rep(i,0,n-1){
rep(j,0,2){
sci(a[i][j]);
}
}
memset(dp,128,sizeof dp);
rep(j,0,2){
rep(k,0,1){
rep(l,0,1){
dp[0][j][k][l]=a[0][j]-k-l;
}
}
}
rep(i,0,n-2){
int cur=i&1,nex=cur^1;
memset(dp[nex],128,sizeof dp[nex]);
rep(j,0,2){
int f=id[j][0],s=id[j][1];
rep(k,0,M){
rep(l,0,M){
//printf("i:%d j:%d k:%d l:%d dp:%d\n",i,j,k,l,dp[cur][j][k][l]);
rep(m,0,2){
int nf=id[m][0],ns=id[m][1];
int vf=(nf==j?1:(nf==f?k+(k>0):l+(l>0)));
int vs=(ns==j?1:(ns==f?k+(k>0):l+(l>0)));
upd(dp[nex][m][vf][vs],dp[cur][j][k][l]+a[i+1][m]-vf-vs);
}
}
}
}
}
int ans=0;
rep(j,0,2){
rep(k,0,M){
rep(l,0,M){
upd(ans,dp[(n-1)&1][j][k][l]);
}
}
}
pte(ans);
}
return 0;
}