The Specials Menu LightOJ - 1025
题意:在给定的字符串中删去一些字符,使其成为回文串(不能全部都删)。求方案数。
方法:常规的区间dp。ans[i][j]表示在i到j的串中删去一些使得成为回文串的方案数。
对于长度为1的串,显然只有1种方法(只保留自身)。
对于长度大于1的串:
可以删去最左侧字符(方案数ans[i+1][j]),也可以删去最右侧字符(方案数ans[i][j-1])。初步的答案也就是这两者相加。但是这两者有重复的部分,就是ans[i+1][j-1],需要再减去。
如果第i个字符和第j个相同,那么又多了两种选择,第一种是只保留左右两个(1种),第二种是去掉左右两个(ans[i+1][j-1])。
错误原因:
1. 忘开longlong
2. (本地)并不明白删去最左侧和最右侧的字符得到的方案的重叠部分是哪个。看了题解以后瞬间理解。
3. (本地,更早)当成与POJ-1141相同的,然而事实上完全不同
1 #include<cstdio> 2 #include<cstring> 3 typedef long long LL; 4 LL T,TT,len; 5 char s[100]; 6 LL ans[110][110]; 7 LL get(LL l,LL r) 8 { 9 if(l>r) return 0; 10 if(l==r) return 1; 11 if(ans[l][r]) return ans[l][r]; 12 LL i,sum=get(l+1,r)+get(l,r-1)-get(l+1,r-1); 13 // for(i=l;i<r;i++) 14 // sum+=get(l,i)+get(i+1,r); 15 //***1.删左边get(l+1,r)或删右边get(l,r-1),重复的是get(l+1,r-1);2.左右都删,或只保留左右(要求左右相同) 16 if(s[l]==s[r]) sum+=get(l+1,r-1)+1; 17 return ans[l][r]=sum; 18 } 19 int main() 20 { 21 scanf("%lld",&T); 22 for(TT=1;TT<=T;TT++) 23 { 24 scanf("%s",s+1); 25 len=strlen(s+1); 26 memset(ans,0,sizeof(ans)); 27 printf("Case %lld: %lld ",TT,get(1,len)); 28 } 29 return 0; 30 }