简单DP,貌似不水的DP自己也做不出来啊,自己又只能刷出2水题啊,网络赛怎么办啊,求大神们赐教啊,努力什么的都有。
题意:给你个字符串,你在里面找有多少种不同的字符串。
注意点:这个MOD的要在里面加上个MOD,不然小心成负值,本人就因为这样wa2次,如果注意到的大神们请别笑我,本人很水。
思路:
状态转移方程: if(str[i]==str[ent]) { dp[i][ent] = (dp[i+1][ent-1] + 1 + dp[i][ent-1]+dp[i+1][ent]-dp[i+1][ent-1]); } else { dp[i][ent] = (dp[i+1][ent]+dp[i][ent-1]-dp[i+1][ent-1]); }
dp[i][j]表示头为i,尾为j的字符串里面包含的回文串的个数。 我来解释下上面这个关系吧,(ent = j)
①:如果str[i]==str[j];这时dp[i+1][ent-1]中所有的都可以加上这对,并且这对单独可以构成一个回文串,所以有dp[i+1][j-1]+1,这个需要考虑只包括str[i]或者str[j],然后减去dp[i+1][j-1]这个重复的部分。
②:如果没有str[i]==str[j]的话,直接dp[i+1][ent]+dp[i][ent-1]-dp[i+1][ent-1] 只包含其边值一个的,然后减去重复的部分。
#include<cstdio>
#include<cstring>
#include<iostream>
#define MOD 10007
#define N 1010
using namespace std;
long long dp[N][N];
char str[N];
int main(void)
{
int test;
int v = 0;
cin>>test;
while(test--)
{
scanf("%s",str+1);
int len = strlen(str+1);
memset(dp,0,sizeof(dp));
for(int i=1;i<=len;++i)
{
dp[i][i] = 1;
}
for(int i=1;i<len;++i)
if(str[i]==str[i+1])
dp[i][i+1] = 3;
else
dp[i][i+1] = 2;
for(int k=2;k<len;++k)
for(int i=1;i+k<=len;++i)
{
int ent = i+k;
if(str[i]==str[ent])
{
//long long g = dp[i+1][k-1];
dp[i][ent] = (dp[i+1][ent-1] + 1 + dp[i][ent-1]+dp[i+1][ent]-dp[i+1][ent-1]+MOD)%MOD;
}
else
{
dp[i][ent] = (dp[i+1][ent]+dp[i][ent-1]-dp[i+1][ent-1]+MOD)%MOD;
}
}
long long ans = (dp[1][len])%MOD;
cout<<"Case "<<++v<<": "<<ans<<endl;
}
return 0;
}