区间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; }