2017年08月13日 基础dp训练
1:
思路 最大子矩阵和的方法和最大字段和一样
可是我一开始还是不会。。
int a[mxn][mxn];
int sum[mxn][mxn];
int main(){
int n;
while(~sf("%d",&n)){
mem(sum[0],0);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
sf("%d",&a[i][j]);
sum[i][j]=sum[i-1][j]+a[i][j];
}
}
int ans=-inf;
for(int i=1;i<=n;++i){
for(int j=i;j<=n;++j){
int t=0;
for(int k=1;k<=n;++k){
t+=sum[j][k]-sum[i][k];
ans=max(ans,t);
if(t<0)t=0;
}
}
}
pf("%d\n",ans);
}
}
2:https://vjudge.net/contest/177552#problem/F
太坑了。。。
吧int 改为short 这样就不会爆内存。。。
char s[mxn];
short dp[mxn][mxn];
int main(){
int n;
while(~sf("%d",&n)){
sf("%s",s+1);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(j<=i)dp[i][j]=0;
else dp[i][j]=6000;
}
}
for(int len=2;len<=n;++len){
for(int i=1;i<=n-len+1;++i){
int j=i+len-1;
if(s[i]==s[j])dp[i][j]=dp[i+1][j-1];
if(dp[i+1][j]+1<dp[i][j])dp[i][j]=dp[i+1][j]+1;
if(dp[i][j-1]+1<dp[i][j])dp[i][j]=dp[i][j-1]+1;
//dp[i][j]=min(dp[i][j],min(dp[i+1][j]+1,dp[i][j-1]+1));
//pf("%d ",dp[i][j]);
}
}
cout<<dp[1][n]<<'\n';
}
}
还是学师兄的吧。。用的是吧 字符串反过来,变为求LCS。。。
然后用滚动数组优化
char s[mxn];
int dp[2][mxn];
int main(){
int n;
while(~sf("%d",&n)){
sf("%s",s+1);
mem(dp,0);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
dp[i%2][j]=max(dp[(i+1)%2][j],dp[i%2][j-1]);
dp[i%2][j]=max(dp[i%2][j],dp[(i+1)%2][j-1]+(s[i]==s[n-j+1]));
}
}
pf("%d\n",n-dp[n%2][n]);
}
}
https://vjudge.net/contest/177552#problem/G
这个应该就只是一个很简单的LCS的变形啊。为什么我老是觉的空字符没法处理。。。
char s[mxn],t[mxn];
int dp[mxn][mxn];
int val[5][5]={
5,-1,-2,-1,-3,
-1,5,-3,-2,-4,
-2,-3,5,-2,-2,
-1,-2,-2,5,-1,
-3,-4,-2,-1,-5
};
int f(char x){
if(x=='A') return 0; if(x=='C') return 1; if(x=='G') return 2;
if(x=='T') return 3;
if(x==' ') return 4;
}
int main(){
int T;sf("%d",&T);
while(T--){
int n,m;
sf("%d %s",&n,s+1);sf("%d %s",&m,t+1);
for(int i=1;i<=n;++i)
dp[i][0]=dp[i-1][0]+val[f(s[i])][f(' ')];
for(int i=1;i<=m;++i)
dp[0][i]=dp[0][i-1]+val[f(t[i])][f(' ')];
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
dp[i][j]=max(dp[i-1][j]+val[f(s[i])][f(' ')],dp[i][j-1]+val[f(t[j])][f(' ')]);
dp[i][j]=max(dp[i-1][j-1]+val[f(s[i])][f(t[j])],dp[i][j]);
}
}
pf("%d\n",dp[n][m]);
}
}
https://vjudge.net/contest/177552#problem/J
两边弄一下LIS。。
顺便回顾下那个二分法的LIS
double a[N];
double g1[N],g2[N];
int dp1[N],dp2[N];
int main(){
int n;
while(~sf("%d",&n)){
mem(dp1,0);mem(dp2,0);
for(int i=1;i<=n;++i)g1[i]=inf,g2[i]=inf;
rep(i,1,n)sf("%lf",&a[i]);
for(int i=1;i<=n;++i){
int k=lower_bound(g1+1,g1+1+n,a[i])-g1;
g1[k]=a[i];
dp1[i]=k;
}
for(int i=n;i>=1;--i){
int k=lower_bound(g2+1,g2+1+n,a[i])-g2;
g2[k]=a[i];
dp2[i]=k;
}
int ans=0;
for(int i=1;i<=n;++i){
for(int j=i+1;j<=n;++j){
ans=max(ans,dp1[i]+dp2[j]);
}
}
pf("%d\n",n-ans);
}
}
这题做过,,这次差一点。。我不应该a[i]-=15,… 都不知道自己为什么要这样。。
http://blog.csdn.net/libin56842/article/details/21116143
int a[N],b[N];
int dp[25][M];
int main(){
int n,m;
while(~sf("%d%d",&n,&m)){
rep(i,1,n){sf("%d",&a[i]);}
rep(i,1,m){ sf("%d",&b[i]); }
mem(dp,0);dp[0][8000]=1;
for(int i=1;i<=m;++i){
for(int j=0;j<=16000;++j){//平衡的地方。。
if(dp[i-1][j]){//优化,有没有都可以,更快。
for(int k=1;k<=n;++k){
dp[i][j+b[i]*a[k]]+=dp[i-1][j];//注意方向
}
}
}
}
pf("%d\n",dp[m][8000]);
}
}
https://vjudge.net/contest/177552#problem/O
不会。。没想都居然最后真的一个一个枚举当前的是不是合适的。
int a[N],c[N];
bool dp[M];
int sum[M];
int main(){
int n,m;
while(~sf("%d%d",&n,&m)&&n+m){
rep(i,1,n){sf("%d",&a[i]);}
rep(i,1,n){sf("%d",&c[i]);}
mem(dp,false);
int ans=0;dp[0]=true;
for(int i=1;i<=n;++i){
mem(sum,0);
for(int j=a[i];j<=m;++j){
if(!dp[j]&&dp[j-a[i]]&&sum[j-a[i]]<c[i]){
dp[j]=true;
sum[j]=sum[j-a[i]]+1;
++ans;
}
}
}
pf("%d\n",ans);
}
}
https://vjudge.net/contest/177552#problem/P
不懂为何这题又是前推式才过了。。。我的有什么错误码。。。
可能我的题意没搞清楚,应该每一个组都要有一个花的。(还真的是。)
int a[N][N];
int dp[N][N];
int main(){
int n,m;
while(~sf("%d%d",&n,&m)){
rep(i,1,n){ rep(j,1,m){ sf("%d",&a[i][j]); } }
mem(dp,0);
int ans=0;
for(int i=1;i<=n;++i)dp[i][i]=dp[i-1][i-1]+a[i][i];
for(int i=1;i<=n;++i){
for(int j=i+1;j<=m;++j){
dp[i][j]=max(dp[i][j-1],dp[i-1][j-1]+a[i][j]);
}
}
/*
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
dp[i][j]=max(dp[i][j-1],max(dp[i][j],dp[i-1][j-1]+a[i][j]));
}
}*/
pf("%d\n",dp[n][m]);
}
}
https://vjudge.net/contest/177552#problem/Q
这题感觉枚举起点和终点会炸。。而且我的代码太丑了。。
看了师兄的。。挺好的。。
char t[N];
char word[N*2][N];
int len[N*2];
int dp[N];
int main(){
int l,m;
while(~sf("%d%d",&m,&l)){
sf("%s",t+1);
rep(i,1,m){sf("%s",word[i]+1);len[i]=strlen(word[i]+1);}
for(int i=1;i<=l;++i){
dp[i]=dp[i-1];
for(int j=1;j<=m;++j){
if(i>=len[j]&&word[j][len[j]]==t[i]){
int r=i-1,tmp=len[j]-1;
while(r&&tmp)if(word[j][tmp]==t[r--])--tmp;
if(!tmp&&dp[r]+len[j]>dp[i])dp[i]=dp[r]+len[j];
}
}
}
pf("%d\n",l-dp[l]);
}
}