9.6 动规训练 题解
----Frosty_Jackal
定义Dpmax[i][j] 表示l~r之间最大的得分,由题意得拆环为链,将1~n的枚举范围扩大到1~2*n ,外层枚举区间长,内层枚举l,在l~r之间设置断点 dpmax[l][r]=max(~,dpmax[l][k]+dpmax[k+1][r]),在内层的最后加上l到r的区间之和,代表此次合成取得的得分;
最小值同理,答案为i=1~n 之间 ,dp[i][i+n-1];
先将所有S相加,若为奇数直接输出0 。 。 。将sum=sum/2,dp[0]=1,将容量设为sum应用0-1背包,最终答案除以2即可。
dp[0]=1;
for(int i=1;i<=n;++i)
for(int j=sum;j>=w[i];j--)
dp[j]+=dp[j-w[i]];
先按左、右端点升序排序,dp[i]=max(dp[j]+a[i].r-a[i].l,dp[i]) 注意j可以为0,此为抛弃前面的所有场次而只选当前场次,ans等于dp1~n的最大值
第一维枚举x1+y1,第二维枚举x1,第三维枚举 x2,看做两个纸条都由1,1传递到m,n。
如X1==x2 且x1+y1不为 n+m,
dp[i][x1][x2]=max(~,dp[i-1][x1][x2],dp[i-1][x1-1]dp[x2-1],dp[i-1][x1][x2-1],dp[i-1][x1-1][x2];
注意x1>=1,>=i-n,<=(i-1),<=m,x2>=1,>=i-n,<=i-1,<=m;
答案是dp[n+m][m][m];
由于T<=1e6
对于每一秒都去枚举,走路和跑步分别为s1,s2。
int m,s,t;
cin>>m>>s>>t;
int s1=0,s2=0;
for(int i=1;i<=t;i++)
{
s1+=17;
if(m>=10) {s2+=60;m-=10;}
else m+=4;
if(s2>s1) s1=s2;
if(s1>s)
{
cout<<"Yes"<<endl<<i<<endl;
return 0;
}
}
cout<<"No"<<endl<<s1<<endl;
return 0;
区间DP,先预处理2的1~m次幂p[],每行读入整行num,将dp数组赋予极小值,dp[L][R]由num[l]*p[k]+dp(l+1,r),dp(l,r-1)+num[r]*p[k]转移;其中k=m-(R-L) { 模拟易得出的规律 }
由于由未知状态转移至当前,故采用记忆化搜索的方式,当dp[l][r]时return ;
#define bll __int128
bll dp(int L,int R)
{
if(f[L][R]!=-1) return f[L][R];
if(R-L>=1) f[L][R]=max(num[L]*p[k]+dp(L+1,R),dp(L,R-1)+num[R]*p[k]);
else f[L][R]=num[L]*p[k];
return f[L][R];
}
注意答案较大,但__int128足够。__int128需用快读快写,而且需要特判ans=0时putchar(‘0’)
if(!ans) printf("0");(此快写无法读出0)
void print(bll x)
{
if(!x) return ;
if(x) print(x/10);
putchar(x%10+'0');
}
inline int read()
{
int X=0,w=1;
char ch=getchar();
while(ch<'0' || ch>'9' ) {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<= '9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
Dj算法,注意只能由编号小的转移而来!
Dp[i][j]为a 1~i 与b 1~j 最长公共子序列的长度,可以得出dp[i][j]=max{dp[i-1][j],dp[i][j],dp[i-1][j-1](当a[i]==b[j]成立)},目标dp[n][m].