您的位置:首页 > 其它

HDU 5763 Another Meaning dp+字符串hash || DP+KMP

2016-08-22 19:22 316 查看
题意:给定一个句子str,和一个单词sub,这个单词sub可以翻译成两种不同的意思,问这个句子一共能翻译成多少种不能的意思

例如:str:hehehe sub:hehe 那么,有**he、he**、和hehehe三种不同的意思,

考虑一下aaadaaa这种情况?sub:aa 前面的aaa有三种,后面的aaa有三种,所以一共应该是有9种情况。

可以考虑成3*3=9

如果你考虑分块去相乘的话,那么恭喜你,你GG了。因为这样写非常复杂,而且非常难判断。

可以考虑下dp,因为注意到,它每个单词只有两种状态,要么转换成其他意思,要么就保留原意。

记dp[i]为匹配到str的第i个字符,所拥有的方案数,那么,如果不转换意思,dp[i] = dp[i-1]

就是方案数是没增加的,还是原来拥有的总数。

那么考虑转义。需要str[i-lensub+1...i]这段字符和sub一模一样,你才能转义把?

这里可以用字符串hash的方法O(1)判断

那么dp[i] += dp[i-lenstub];

就是在屏蔽str[i-lensub+1...i]这段字符的情况下,拥有的方案数,+我的转义,就是一种全新的方案,所以匹配到这个字符的时候,方案数要加上屏蔽这段字符前拥有的方案数

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (1<<28)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int MOD  = 10007;
const int maxn = 200000+20;
char str[maxn];
void get_next (char sub[],int nextliu[],int len)
{
nextliu[1]=0;
int i=1,j=0;
while (i<=len)
{
if (j==0 || sub[i]==sub[j])
{
nextliu[++i]=++j;
}
else j=nextliu[j];
}
return ;
}
int nextliu[maxn];
int dp[maxn]={0};
void work ()
{
int lenstr;
scanf ("%d",&lenstr);
scanf ("%s",str+1);
get_next(str,nextliu,lenstr);
/*
for (int i=1;i<=lenstr;i++)
{
printf ("%d ",next[i]);
}
printf ("\n");*/

int ans=0;
for (int i=1;i<=lenstr;i++)
{
dp[i]=dp[nextliu[i+1]-1]+1;
ans += dp[i];
ans %= MOD;
}
printf ("%d\n",ans);
return ;
}

int main ()
{
#ifdef local
freopen("data.txt","r",stdin);
#endif
int t;
scanf ("%d",&t);
while (t--)
{
work ();
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: