-
时间:2016-05-04 16:51:34 星期三
-
题目编号:[2016-05-04][codeforces][666A - Reberland Linguistics]
-
题目大意:一个单词由长度不少于5的词根和长度为2或3的若干个后缀组成,并且两个相邻的后缀不能一样,给定一个单词,问这个单词总共可以有多少个后缀
-
分析:
- 类似dp 的思想,dp[i] 表示第i个位置到字符串结束能否划分成合法后缀,
- 那么dp[i] = dp[i +t] ∧ ( dp[i + 5] ∨ 子串(i,t) != 子串 (i + t , t)); t == 2 或 3
- 即,从后往前扫,每增加一个字符,就判断由它开始的长度为2 和 3的后缀 和剩下部分 组成的后缀 是否合法
- 新后缀是否合法,
- 使用这个后缀后,剩下部分仍然能正常分割成2 或 3的若干个后缀
- 这个后缀和下一个那个后缀不一样(只要存在不一样的分法就可以)
- 这个后缀和下一个后缀长度一样:直接比较
- 长度不一样,显然成立,但是要在往前数5位剩下的能合法分割,即dp[I+ 5]为真的情况才行
-
遇到的问题:
- 判断当前后缀和下一个后缀是否一样的时候,如果用子串来比较的话,刚开始的时候,i + 2 > 长度 的时候会出错
- 解决办法是,不生成子串,而是通过find函数,来查找下一个和它相同的字符串的位置
- 初始化 dp[长度] = 0;
#include<iostream>
#include<string>
#include<set>
#include<cstring>
using namespace std;
set<string> s;
const int maxn = 1E4 + 10 ;
int dp[maxn];
int main(){
string str;
cin>>str;
memset(dp,0,sizeof(dp));
str = str.substr(5);
int n = str.length();
string tmp;
dp[n] = 1;
for(int i = n - 1; i >= 0 ; --i){
for(int l = 2 ; l <= 3 ; ++l){
tmp = str.substr(i, l);
if(( str.find(tmp,i + l) != i + l || dp[i + 5] ) && dp[i + l] ){
s.insert(tmp);
dp[i] = 1;
}
}
}
cout<<s.size()<<"\n";
for(set<string>::iterator its = s.begin(); its != s.end();++its){
cout<<*its<<"\n";
}
return 0;
}
时间: 2024-10-06 16:25:55