区间dp
http://acm.hdu.edu.cn/showproblem.php?pid=4632
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1009;
char str[maxn];
int dp[maxn][maxn];
char sum[26][maxn];
int Q(int l,int r){
if(l>r) return 0;
return dp[l][r];
}
const int mod = 10007;
void add(int &k,int val){
k+=val;
if(k>=mod) k-=mod;
if(k<0) k+=mod;
}
int main()
{
int cas = 1;
int T;scanf("%d",&T);
while(T--){
scanf("%s",str+1);
memset(dp,0,sizeof(dp));
int len = strlen(str+1);
for(int k=1;k<=len;k++){
for(int i=1;i+k-1<=len;i++){
int l = i,r = i+k-1;
add(dp[l][r],Q(l,r-1));
add(dp[l][r],Q(l+1,r));
add(dp[l][r],-Q(l+1,r-1));
if(str[l]==str[r]) {
add(dp[l][r],1);
add(dp[l][r],Q(l+1,r-1));
}
}
}
printf("Case %d: ",cas++);
printf("%d\n",dp[1][len]);
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=4745
这题我企图倍增后逆序求两个的最长公共子序列再骚搞,然而是个错的,不能用dp[i][j]求区间10到i,10到j的最长子序列
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2009;
int a[maxn];
int dp[maxn][maxn];
int main()
{
int n;
while(scanf("%d",&n)){
if(n==0) break;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i+n] = a[i];
}
for(int k=1;k<=2*n;k++){
for(int i=1;i<=2*n;i++){
int l=i,r = i+k-1;
dp[l][r] = 0;
if(l==r)
dp[l][r]++;
else if(a[l]==a[r])
dp[l][r] = dp[l+1][r-1]+2;
dp[l][r] = max(dp[l][r],dp[l+1][r]);
dp[l][r] = max(dp[l][r],dp[l][r-1]);
}
}
int ans = 0;
for(int i=1;i<=2*n;i++){
if(i+n-1<=2*n)
ans = max(ans,dp[i][i+n-1]);
if(i+n-2<=2*n)
ans = max(ans,dp[i][i+n-2]+1);
}
printf("%d\n",ans);
}
return 0;
}
http://hihocoder.com/problemset/problem/1636
因为有连续性这个条件所以枚举可以省掉一维,本来想k堆转移的时候还要考虑左边1,2,3,4.。。。k-1堆,右边k-1,k-2,...1堆的枚举,实际上不用,因为总有最左的一堆,只要枚举最左堆所在的区间就行了
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn = 109;
int a[maxn];
const int inf = 0x3f3f3f3f;
int sum[maxn];
int dp[maxn][maxn][maxn];
int main()
{
int n,l,r;
while(~scanf("%d%d%d",&n,&l,&r)){
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i] = sum[i-1]+a[i];
}
for(int k=1;k<=n;k++){
for(int i=1;i+k-1<=n;i++){
int ll = i,rr = i+k-1;
if(ll==rr) dp[ll][rr][1] = 0;
else
dp[ll][rr][1] = (k<=r && k>=l)?(sum[rr]-sum[ll-1]):inf;
for(int j=2;j<=k;j++){
if(rr-ll+1==j){
dp[ll][rr][j] = 0;
continue;
}
for(int z = ll;z+1<=rr;z++){
dp[ll][rr][j] = min(dp[ll][rr][j],dp[ll][z][1]+dp[z+1][rr][j-1]);
}
}
for(int j=2;j<=k;j++)if(j<=r && j>=l){
dp[ll][rr][1] = min(dp[ll][rr][1],dp[ll][rr][j]+sum[rr]-sum[ll-1]);
}
}
}
int ans = dp[1][n][1];
printf("%d\n",ans==inf?0:ans);
}
return 0;
}

浙公网安备 33010602011771号