传送门
KMP+AC自动机 ,AC自动机还没学T_T
A - 逆序单词 HihoCoder - 1366
解:正序插入得同时,反向查询字符串是否存在
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const double eps=1e-9;
const int maxn=1e6+5;
//il int Add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll x,int y) {return x*y>=mod?x*y%mod:x*y;}
int n,ans=0;
int tree[maxn][30],tot=0;
bool flag[maxn];
il void add(char *s){
int root=0,id,len=strlen(s);
for(int i=0;i<len;++i){
id=s[i]-'a';
if(!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
}
flag[root]=true;
}
il bool find(char *s){
int root=0,id,len=strlen(s);
for(int i=len-1;i>=0;--i){
id=s[i]-'a';
if(!tree[root][id]) return false;
root=tree[root][id];
}
if(flag[root]) return true;
else return false;
}
char s[105];
int main() {
sc(n);
rep(i,1,n){
scanf("%s",&s);
add(s);
if(find(s)) ans++;
}
cout<<ans<<endl;
return 0;
}
B - Xor Sum HDU - 4825
解:每个数都按32位插入,查找就优先!该位 即可。
#include<iostream>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int maxn=100000*32+100;
//il int Add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll x,int y) {return x*y>=mod?x*y%mod:x*y;}
int tree[maxn][2],tot=0,flag[maxn];
il void add(int x) {
int root=0,bit;
for(int i=31; i>=0; --i) {
bit=(x>>i)&1;
if(!tree[root][bit]) {
tree[root][bit]=++tot;
tree[tot][0]=tree[tot][1]=0;
}
root=tree[root][bit];
}
flag[root]=x;
}
il int solve(int x) {
int root=0,bit;
for(int i=31; i>=0; --i) {
bit=!((x>>i)&1);
if(tree[root][bit]) root=tree[root][bit];
else root=tree[root][bit^1];
}
return flag[root];
}
int main() {
int T,x,n,m,cnt=0;
sc(T);
while(T--) {
tot=0;
tree[0][0]=tree[0][1]=0;
printf("Case #%d:\n",++cnt);
SC(n,m);
rep(i,1,n) sc(x),add(x);
rep(i,1,m) sc(x),printf("%d\n",solve(x));
}
return 0;
}
C - Hyper Prefix Sets UVA - 11488
解:记录一波到该前缀得个数即可。
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const double eps=1e-9;
const int maxn=1e6+5;
//il int Add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll x,int y) {return x*y>=mod?x*y%mod:x*y;}
int T,n,tree[maxn][2];
int tot=0,ans,num[maxn];
char s[205];
void init(){
tot=0,tree[0][0]=tree[0][1]=0,ans=-1;
}
void add(char *s){
int root=0,id,len=strlen(s);
for(int i=0;i<len;++i){
id=s[i]-'0';
if(!tree[root][id]){
tree[root][id]=++tot;
tree[tot][0]=tree[tot][1]=num[tot]=0;
}
root=tree[root][id];
num[root]++;
ans=max(ans,num[root]*(i+1));
}
}
int main() {
sc(T);
while(T--) {
init();
sc(n);
rep(i,1,n) scanf("%s",&s),add(s);
cout<<ans<<endl;
}
return 0;
}
D - Cyclic Nacklace HDU - 3746
解:先跑一遍KMP,求得nxt[slen] 即最大前后缀,len=slen-nxt[slen] 就是最小循环节的长度,然后讨论一下。
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const double eps=1e-9;
const int maxn=1e5+5;
//il int Add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll x,int y) {return x*y>=mod?x*y%mod:x*y;}
int nxt[maxn];
void getnext(char *s) {
nxt[0]=-1;
int j=0,k=-1,len=strlen(s);
while(j < len) {
if(k==-1 || s[j]==s[k]) {
++k,++j;
if(s[j] != s[k]) {
nxt[j]=k;
} else nxt[j]=nxt[k];
} else k=nxt[k];
}
}
int T,n;
char s[maxn];
int main() {
sc(T);
while(T--) {
scanf("%s",&s);
getnext(s);
int slen=strlen(s),len=slen-nxt[slen];//最小循环节的长度
if(nxt[slen]==0) cout<<slen<<endl;
else if(slen%len==0 && (slen/len)>=2) cout<<0<<endl;
else cout<<len-(nxt[slen]%len)<<endl;
}
return 0;
}
后面,我还是先去学AC自动机