[LA3942]Remember the Word

发布于 2017-12-23  133 次阅读



题目(vjudge)
首先要明白这题是dp,
用dp[i]表示从i开始的字符串有多少种分解方法,
转移方程很简单,dp[i]+=dp[i+strlen(x)] | x串为当前串的前缀。
但是我们不会去枚举每个x串,否则时间爆炸。
解决方法就是将所有x串加到一棵Trie里面,
然后用i串去查找,只要到了某个节点上有x串,就执行转移方程。
完毕。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <string>
#include <climits>
#define ll long long
#define llmax LONG_LONG_MAX
#define llmin LONG_LONG_MIN
#define N 300010
using namespace std;
template <class _E> inline void read(_E &e)
{
	e=0;bool ck=0;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')ck=1;ch=getchar();}
	while(ch>='0'&&ch<='9'){e=e*10+ch-'0';ch=getchar();}
	if(ck)e=-e;
}
const int mod=20071027LL;
int S,L;
int dp[N];
struct Trie{
	int ch[N+100005][30];
	int val[N+100005];
	int siz;
	void data_clear(){siz=1;memset(ch,0,sizeof ch);memset(val,0,sizeof val);}
	int tr(char x){return x-'a';}
	void charin(char *s,int v)
	{
		int u=0;
		for (int i=0;i<v;++i)
		{
			int c=tr(s[i]);
			if (!ch[u][c])
			{
				memset(ch[siz],0,sizeof ch[siz]);
				val[siz]=0;
				ch[u][c]=siz++;
			}
			u=ch[u][c];
		}
		val[u]=v;
	}
	void query(char *s,int x)
	{
		int u=0;
		for (int i=x;i<L;++i)
		{
			int c=tr(s[i]);
			if (!ch[u][c]) break;
			u=ch[u][c];
			if (val[u]) dp[x]+=dp[x+val[u]],dp[x
		}
	}
}trie;
char s[N];
int main()
{
	int kas=0;
	while (scanf(
	{
		L=strlen(s);
		memset(dp,0,sizeof dp);
		trie.data_clear();
		read(S);
		char s0[105];
		for (int i=1;i<=S;++i)
		{
			scanf(
			trie.charin(s0,strlen(s0));
		}
		dp[L]=1;
		for (int i=L-1;i>=0;--i) trie.query(s,i);
		printf("Case
	}
	return 0;
}