poj我怎么一天到晚做的全是普及组CSP-J类的题目啊
发现回文中心肯定是在串内部的。而一个串两端如果不一样,肯定是要动的。也就是说$S_{i...j}$只要动一端,看剩下来部分minvalue。于是这是一个基于区间的字符串DP。
设$f_{i,j}$表示区间为回文串的最小代价,如果一个串两头不同,则从$f_{i+1,j}+del_i/add_i和f_{i,j-1}+del_j/add_j$里择优转移。如果对于一个串两头相同,可以证明是直接取$f_{i+1,j-1}$更优的而不是去掉一端更优。
边界显然。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define dbg(x) cerr << #x << " = " << x <<endl 7 using namespace std; 8 typedef long long ll; 9 typedef double db; 10 typedef pair<int,int> pii; 11 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 12 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;} 16 template<typename T>inline T read(T&x){ 17 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 18 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 19 } 20 const int N=2000+7,INF=0x3f3f3f3f; 21 int f[N][N]; 22 char s[N],t[N]; 23 int del[N],add[N]; 24 int n,m; 25 int dp(int l,int r){ 26 if(f[l][r]<INF)return f[l][r]; 27 if(r<=l)return f[l][r]=0; 28 if(s[l]^s[r]) 29 MIN(f[l][r],dp(l,r-1)+_min(del[s[r]],add[s[r]])),MIN(f[l][r],dp(l+1,r)+_min(del[s[l]],add[s[l]])); 30 else 31 MIN(f[l][r],dp(l+1,r-1)); 32 return f[l][r]; 33 } 34 35 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout); 36 read(n),read(m); 37 scanf("%s",s+1); 38 for(register int i=1;i<=n;++i)scanf("%s",t),read(add[t[0]]),read(del[t[0]]); 39 memset(f,0x3f,sizeof f); 40 return printf("%d\n",dp(1,m)); 41 }View Code
总结:这种一个字符串满足某某性质求修改代价的,如果$|S|$小可以考虑平方复杂度,通过区间DP来合并信息,当然更多的是看情况推性质做决定。