求最下循环节问题,上节课讲过了,没有理解的话,记住公式.
#include<iostream>
#include<cstring>
using namespace std;
string s;
int nxt[1000006];
int len;
int sim=1;
void get_next()
{
nxt[0]=-1;
int i=0,k=-1;
while(i<s.size())
{
if(k==-1||s[i]==s[k])
{
i++;
k++;
nxt[i]=k;
}
else k=nxt[k];
}
}
int main()
{
while(cin>>len)
{
if(len==0)return 0;
cin>>s;
get_next();
cout<<"Test case #"<<sim++<<endl;
for(int i=2;i<=len;i++)
{
int lens=i;
if(lens%(lens-nxt[i])==0&&nxt[i]!=0)//这里就是公式 当可以整除表明存在最小循环节
{
cout<<lens<<" "<<lens/(lens-nxt[i])<<endl;
}
}
cout<<endl;
}
return 0;
}
题目大意:就是输多组0 1数据,任意一组数据不能成为另一种的前缀
思路:建立trie树,每次插入的时候查询一下是否会有新字符要插入,如果有就符合,没有的话当前要插入的字符串就是其他字符串的前缀。
注意这道题数据很小:
0000
010
10
01
应该输出------not---------
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100006;
string s;
int cnt[N];
int trie[N][3];
int index;
int k=1;
int f=1;
void init()
{
f=1;
index=0;
for(int i=0;i<=N;i++)
{
cnt[i]=0;
for(int j=0;j<3;j++)
trie[i][j]=0;
}
}
int insert(string t)
{
int p=0;
for(int i=0;i<t.size();i++)
{
int c=t[i]-'0';
if(!trie[p][c])trie[p][c]=++index;
p=trie[p][c];
if(cnt[p])return 0;
}
cnt[p]++;
return 1;
}
int query(string t)
{
int p=0;
for(int i=0;i<t.size();i++)
{
int c=t[i]-'0';
if(!trie[p][c])return 1;//有新单词要插入 返回1
p=trie[p][c];
if(cnt[p])return 0;//当前字符串在之前已经有了返回0
}
return 0;//如果这个字符串是之前的前缀 返回0
}
int main()
{
while(cin>>s)
{
if(s=="9")
{
if(f)cout<<"Set "<<k++<<" is immediately decodable"<<endl;
else cout<<"Set "<<k++<<" is not immediately decodable"<<endl;
init();
continue;
}
if(f)
{
f=query(s);
insert(s);
}
}
return 0;
}
题目大意:找字符串的最独一无二的前缀
思路:trie树,建立的时候每个节点都打上标记,查询的时候碰到标记值为1的时候就是独一无二的前缀。碰到标记值大于1的进行下一次循环。
#include<iostream>
#include<string>
#include<stdio.h>
using namespace std;
const int N=2e6+5;
int trie[N][27];
int cnt[N];
int index;
char p[N][50];
void insert(string s)
{
int p=0;
for(int i=0;i<s.size();i++)
{
int c=s[i]-'a';
if(!trie[p][c])trie[p][c]=++index;
p=trie[p][c];
cnt[p]++;
}
}
void query(string s)
{
int p=0;
for(int i=0;i<s.size();i++)
{
int c=s[i]-'a';
p=trie[p][c];
if(cnt[p]>1)cout<<s[i];
if(cnt[p]==1){
cout<<s[i];return;}
}
}
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int line=0;
while(scanf("%s",p[line])!=EOF)/用C的语法写,不然会tle 血的教训
{
line++;
insert(p[line-1]);
}
for(int i=0;i<line;i++)
{
cout<<p[i]<<" ";
query(p[i]);
cout<<"\n";
}
return 0;
}
题目大意:给你一个翻译后的字符串和翻译前的字符串形成字典,输入翻译前的字符串将它进行翻译。
思路:建立trie树,节点值不仅要存标记值,而且还要存进去翻译后的字符串。(注意要用空间建立,第一次写没看见题目给定的范围用数组模拟空间会爆内存)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<map>
using namespace std;
const int N=46;
char op[1000000];
struct trieNode{
int c;
trieNode** son;
int cnt;
string ans;
trieNode(int num)
{
ans="";
c=num;
cnt=0;
son=new trieNode*[N];
for(int i=0;i<N;i++)son[i]=NULL;
}
};
trieNode* root;
void insert(string s,string s1)
{
trieNode* p=root;
for(int i=0;i<s.size();i++)
{
int c=s[i]-'a';
if(!p->son[c])p->son[c]=new trieNode('c');
p=p->son[c];
}
p->cnt++;
p->ans=s1;
}
string query(string s)
{
trieNode* p=root;
for(int i=0;i<s.size();i++)
{
int c=s[i]-'a';
if(!p->son[c])return "";
p=p->son[c];
}
return p->ans;
}
int main()
{
root=new trieNode(0);
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
string s1,s2;
char t;
while(true)
{
t=getchar();
s1="";s2="";
int flag=1;
if(t=='\n')break;
s1+=t;
while(true)
{
t=getchar();
if(t==' '){
flag=0;continue;}
if(t=='\n')break;
if(flag)s1+=t;
else s2+=t;
}
insert(s2,s1);
}
while(scanf("%s",op)!=EOF)//用C写法,不然TLE wa哭了qvq
{
string pri=query(op);
if(pri!="")
cout<<pri<<endl;
else cout<<"eh"<<endl;
}
return 0;
}