紫书训练 8.4

传送门

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自动机

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值