191021-基础测试1

191021-基础测试1

T1 特殊排序

题目描述

写一个程序,对于读入的一对正整数x和y,将这两个数之间(包括这两个数本身)的所有数按下述特别规则排序后输出,该特别规则是按两数倒过来的值进行比较决定其大小,如30倒过来为3,29倒过来为92,则29大于30。

如果倒过来的数和原来的某一个数一样大,则按原来的顺序从小到大排序。比如:原始的数有11和110,则110倒过来是新11,和原来的11相等,则输出的时候11放110前面。

输入格式

输入一行两个正整数x 和 y ,用一个空格隔开(1≤x≤y≤999999999,y-x≤100)。

输出格式

输出输出包括y-x+1行,每行一个正整数,按两数倒过来的值进行比较决定其大小,然后由小到大输出

分析

用结构体的两个域存储原始数和反向数。 按反向数排序后,依次输出原始数

注意

如果倒过来,两者值相等,其相对位置不能改变

题解

#include<bits/stdc++.h>
using namespace std;
int cnt,len,q[10009],a,b;
struct zb
{
	int x,y;
}m[10009];
bool comp(const zb &a,const zb &b)
{
	if(a.x!=b.x) return a.x<b.x;
	return a.y<b.y;
}
void make(int r)
{
	cnt++;
	m[cnt].y=r;
	len=0;
	while(r)
	{
		q[++len]=r%10;
		r/=10;
	}
	for(int i=1;i<=len;i++)
		m[cnt].x=m[cnt].x*10+q[i];
}
int main()
{
	freopen("ssort.in","r",stdin);
	freopen("ssort.out","w",stdout);
	scanf("%d%d",&a,&b);
	for(int i=a;i<=b;i++)
		make(i);
	sort(m+1,m+b-a+2,comp);
	for(int i=1;i<=b-a+1;i++)
		printf("%d\n",m[i].y);
	return 0;
}

T2 部落卫队

题目描述

原始部落 byteland 中的居民们为了争夺有限的资源,经常发生冲突。几乎每个居民都有他的仇敌。部落酋长为了组织一支保卫部落的队伍,希望从部落的居民中选出最多的居民入伍,并保证队伍中任何 2 个人都不是仇敌。

给定 byteland 部落中居民间的仇敌关系,编程计算组成部落卫队的最佳方案。

输入格式

第 1 行有 2 个正整数 n(1<=n<=100) 和 m(1<=n<=3000) ,表示byteland部落中有 n 个居民,居民间有 m 个仇敌关系。居民编号为 1,2,…,n。接下来的 m 行中,每行有2个正整数 u 和 v,表示居民 u 与居民 v 是仇敌。

输出格式

第1行是部落卫队的顶人数;
第2行是卫队组成 xi ,1≤i≤n, 其中 xi =0 表示居民i不在卫队中,xi=1表示居民i在卫队中。

分析

一道搜索原题(但还是没做出来,写的贪心),虽然数据达到了100,但只要加上最优化剪枝就不会t掉。另外一个技巧,f[i]数组相当于一个计数器,表示在已经确定的部落卫队的人中,以i为仇敌的人数,有且只有当f[i]==0时,才能加入卫队。

题外话

该题还能用随机化贪心,用到的函数为random_shuffle(b+1,b+n+1)将原来的数组随机打乱,然后我们按照打乱后的顺序来选,重复200000次,便无线接近于正确答案,代码如下

题解(搜索剪枝)

#include<bits/stdc++.h>
using namespace std;
int maxn,ans,d[109],b[109],a[109][109],n,m,f[109];
void dfs(int dep)
{
	if(dep==n+1&&ans<maxn)
	{
		ans=maxn;
		for(int i=1;i<=n;i++)
			d[i]=b[i];
		return;
	}
	if(maxn+n-dep+1<ans) return;
	if(!f[dep])
	{
		maxn++;
		b[dep]=1;
		for(int i=1;i<=a[dep][0];i++) f[a[dep][i]]+=1;
		dfs(dep+1);
		for(int i=1;i<=a[dep][0];i++) f[a[dep][i]]-=1;
		maxn--;
	}
	b[dep]=0;
	dfs(dep+1);
}
int main()
{
	int x,y;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		a[x][++a[x][0]]=y;
		a[y][++a[y][0]]=x;
	}
	dfs(1);
	printf("%d\n",ans);
	for(int i=1;i<=n;i++)
		printf("%d ",d[i]);
	return 0;
}

附上错误贪心代码

#include<bits/stdc++.h>
using namespace std;
int n,m,bj[101],a[109][109],num,ans[109];
priority_queue<pair<int,int> >q;
int main()
{
	int x,y;
	//freopen("guard.in","r",stdin);
	//freopen("guard.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		a[x][++a[x][0]]=y;
		a[y][++a[y][0]]=x;
	}
	for(int i=1;i<=n;i++)
		q.push(make_pair(-a[i][0],i));
	while(!q.empty())
	{
		int v=q.top().second;
		q.pop();
		if(!bj[v])
		{
			ans[v]=1;
			num++;
			for(int i=1;i<=a[v][0];i++)
				bj[a[v][i]]=1;
		}	
	}
	printf("%d\n",num);
	for(int i=1;i<=n;i++)
		printf("%d ",ans[i]);
	return 0;
}

随机化贪心代码(可以ac)

#include<bits/stdc++.h> //没有判断字典序最大 
using namespace std;
int a[101][101],c[101],bj[101],b[101],n,m,maxn=-100,ans,vis[101];
int main()
{
	int x,y; 
	scanf("%d%d",&n,&m);;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		a[x][++a[x][0]]=y;
		a[y][++a[y][0]]=x;
	}
	for(int i=1;i<=n;i++)
		b[i]=i;
	for(int cas=1;cas<=200000;cas++)
	{
		ans=0;
		memset(vis,0,sizeof(vis));
		memset(bj,0,sizeof(bj));
		random_shuffle(b+1,b+n+1);
		for(int i=1;i<=n;i++)
		{
			if(bj[b[i]]) continue;
			bj[b[i]]=1;
			vis[b[i]]=1;
			ans++;
			for(int j=1;j<=a[b[i]][0];j++)
				bj[a[b[i]][j]]=1;
		}
		if(ans>=maxn)
		{
			maxn=ans;
			for(int i=1;i<=n;i++)
				c[i]=vis[i];
		}
	}
	printf("%d",maxn);
	for(int i=1;i<=n;i++)
		printf("%d ",c[i]);
	return 0;
} 

T3 数字排序

题目描述

国安局情报人员收到了一些特殊的加密信息,这些信息由两个数列 A 和 B 构成,A 中有 N 个数,B 中有 M 个数,把 A 中每一个数分别与 B 中每一个数乘起来得到的 N×M 个数进行从小到大排序后,其中的第 K 个数就是加密信息的原文数字。现在请你帮他解密。

输入格式

第一行是三个整数 N(1≤N≤10000), M(1≤M≤10000), K(1≤K≤N×M)。相邻两个数由一个空格隔开。
第二行是 N 个属于 A 数列的整数 Ai(0≤Ai≤10000),相邻两个数由一个空格隔开。
第三行是 M 个属于 B 数列的整数 Bi(0≤Bi≤10000),相邻两个数由一个空格隔开。

输出格式

输出一个整数,即满足题意的第 K 个数。

分析

二分套二分。设 C=A×B,当 A 是固定 且为非负整数的时候,当 B 增加时,C 不减小,即是函数具有单调性。 因此这个题目可以先将两个数列 A 和 B 分别进行升序排序,然后枚举一个数列 A 的每一 个数,得到 C/A[i],接着通过二分查找(可以用upper_bound函数),在 B 中找出小于或等于 C/A[i]的数有多少个,把 这些个数进行求和,再与 K 比较即可判断二分的上界和下界的变化。二分完成后得到的就是正确答案。
最后分析一下本题的时间复杂度。这种解法总共需要二分答案 log2(max{ai×bi})次, 每次二分答案枚举数组 A 和二分查找数组 B,共操作 n×log2m 次,因此时问复杂度为 O(log2(max{ai×bi})×n×log2m)

题解(使用upper_bound)

#include<bits/stdc++.h>
using namespace std;
int a[10009],b[10009],n,m,k;
bool check(int r)
{
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(a[i]==0)//特判a[i]==0的情况; 
		{
			ans+=m;
			continue;
		}
		int z=r/a[i];
		ans=ans-1+upper_bound(b+1,b+m+1,z)-b;
	}
	if(ans<k) return true;
	return false;
}
int main()
{
	freopen("numsort.in","r",stdin);
	freopen("numsort.out","w",stdout);
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=m;i++)
		scanf("%d",&b[i]);
	sort(a+1,a+n+1);
	sort(b+1,b+m+1);
	int l=a[1]*b[1];
	int r=a[n]*b[m];
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(check(mid))//比第k小数小 
			l=mid+1;
		else
			r=mid;	
	}
	printf("%d",l);
	return 0; 
}

不使用upper_bound

#include<bits/stdc++.h>
using namespace std;

int na,nb,k;                   //数列A,数列B的大小和K
int a[10005],b[10005];         //数列A和数列B

int Find(int x)	                //在B中通过二分查找,求小于等于x的数的个数
{                               //先找小于等于x的最大值Max,则个数=Max的下标L 
	  int L=1,R=nb,mid;         //B数组下标的上界、下界、中间值
	  while(L<R)
	  { 
  	        mid=(L+R+1)>>1;      //得到中间值
    		if(b[mid]<=x)        //b[mid]小于等于x时,在右半区间找(增加),要找最大的
				L=mid;     
			else                 //b[mid]大于x时,在有左半区间找(减少)
				R=mid-1;   
	  }
	  return L;                //返回数列B中小于等于x的数的个数
}

int Count(int x)                 //x为main中二分到的答案
{
	int ret=0;
	for(int i=1;i<=na;i++)        //枚举A中每个数
	{	
		if(a[i]==0)              //如果a[i]为零,
			ret+=nb;             //则a[i]与B中每个数相乘都必然小于等于非负整数x,所以个数为nb
		else
			ret+=Find(x/a[i]);   //如果a[i]不为零,则用Find求出B中小于等于x/a[i]的个数并累加
	}
	return ret;                  //返回累加的个数
}

int main()
{
    freopen("numsort.in","r",stdin);
    freopen("numsort.out","w",stdout);
    scanf("%d%d%d",&na,&nb,&k);                //读入A,B的大小和k
	for(int i=1;i<=na;i++) scanf("%d",&a[i]);   //读入数列A
	for(int i=1;i<=nb;i++) scanf("%d",&b[i]);   //读入数列B

	sort(a+1,a+na+1);          //对A进行排序
	sort(b+1,b+nb+1);          //对B进行排序

	int L=a[1]*b[1];           //二分的下届
	int R=a[na]*b[nb];         //二分的上界
	int mid;                   //中间值
	while(L<R) 
	{
		mid=(L+R)>>1;
		if(Count(mid)>=k)     //如果统计出来的个数大于等于K
			R=mid;            //减少C
		else
			L=mid+1;          //增加C  
	}
	printf("%d\n",L);         //输出答案(第K小值) 
	return 0;
}

T4 单词

题目背景

TJOI2013 DAY1 T3

题目描述

小张最近在忙毕业论文设计,所以一直在读论文。一篇论文是由许多单词组成的。但小张发现一个单词会在论文中出现很多次,他想知道每个单词分别在论文中出现多少次。

输入格式

第一行一个整数 N (N≤200),表示有 N 个单词。接下来 N 行每行一个单词。每个单词都由小写字母(‘a’~’z’)组成。
所有单词构成论文(一行一个单词)。

输出格式

输出 N 个整数,第 i 行的数字表示第 i 个单词在文章中出现了多少次。

分析

后缀数组或 AC 自动机均可解决本题。 我们使用 AC 自动机实现。注意要记录单词的出现位置结束位置,但不能在最后查找, 因为单词出现的次数是从它出现的位置开始算起,即所有单词合成的这篇文章中,处于当前单词之前可能还合成了当前单词,但不计入最后结果。 题目略微表述不清,论文不是所有单词连接在一起的,而是连接处有空格(可从样例看出来)

题解1(AC自动机)

//AC自动机 
#include<bits/stdc++.h>
using namespace std;

vector<int>loc,order;
int n,nxt[1000010][30],fail[1000010],sum[1000010],tot;
bool vis[1000010];

void clean()
{
	memset(sum,0,sizeof(sum));
	memset(fail,0,sizeof(fail));
	memset(nxt,0,sizeof(nxt));
	memset(vis,false,sizeof(vis));
	tot=0;
	loc.clear(); order.clear(); 
	return;
} 
 
void insert(char c[])
{
	int len=strlen(c);
	int now=0,i;
	for (i=0;i<len;++i)
	{
	 	int x=c[i]-'a';
	 	if (!nxt[now][x]) nxt[now][x]=++tot;
	 	sum[nxt[now][x]]++; now=nxt[now][x];
	}
	vis[now]=true;           //标记以当前点为结尾的单词出现过 
	loc.push_back(now);      //标记结尾 
	return;
}

void buildfail()
{
	queue<int>que;
    int i,j;
	for(i=0;i<26;++i) 
	   if(nxt[0][i]) que.push(nxt[0][i]);
	   
	while(!que.empty())
	{
	 	int now=que.front(); que.pop();
	 	order.push_back(now);            //把当前出现的单词存起来 
	 	for(i=0;i<26;++i)
	 	{
	 	 	if(!nxt[now][i])
	 	 	{
				nxt[now][i]=nxt[fail[now]][i];
				continue;
			}
	 	 	int x=nxt[now][i];
	 	 	fail[x]=nxt[fail[now]][i];   //fail里存到当前字母为止的单词的最长后缀 
	 	    que.push(x);                 //将更新出来的单词存入队列(存的是序号) 
	    } 
	} 
	return;
}

void find()
{
	for(int i=order.size()-1;i>=0;--i)
		sum[fail[order[i]]]+=sum[order[i]];
	for(int i=0;i<n;++i)
		printf("%d\n",sum[loc[i]]);
	return;
}
 
int main()
{
    freopen("word.in","r",stdin);
    freopen("word.out","w",stdout);
	clean();
	scanf("%d",&n);
	for(int i=0;i<n;++i)
	{
	    char s1[1000010];
	    scanf("%s",s1);
	 	insert(s1);
	}
	buildfail();
	find();
	return 0;
}

题解2(后缀数组)

#include<string.h>
#include<stdio.h>
#include<algorithm>
#define MAXN 2100000
using namespace std;
class DC3{
	public:
		char* ch;
		int *rank,*SA;
		int n;
		int cnt0,cnt1,cnt2;
		static int sum[MAXN];
		static int tmpSA[MAXN];
		static int tmpRank[MAXN];
		DC3(){}
		DC3(int* _rank,int* _SA,int _n,char* s=NULL){
			rank=_rank;
			SA=_SA;
			n=_n;
			rank[n]=rank[n+1]=-1;
			if(s==NULL) return;
			for(int i=0;i<n;i++)
				rank[i]=s[i];
			ch=s;
		}
		void getH(int* h){
			for(int i=0;i<n;i++){
				if(rank[i]==0){
					h[i]=0;
				}
				else {
					h[i]=(i?max(0,h[i-1]-1):0);
					for(;h[i]<n&&ch[i+h[i]]==ch[SA[rank[i]-1]+h[i]];h[i]++);
				}
			}
		}
		void radixSort(int* rank,int* SA,int n){
			int maxKey=0;
			for(int i=0;i<n;i++){
				sum[rank[SA[i]]+2]++;
				maxKey=max(maxKey,rank[SA[i]]+2);
			}
			for(int i=1;i<=maxKey+1;i++)
				sum[i]+=sum[i-1];
			for(int i=0;i<n;i++){
				tmpSA[sum[rank[SA[i]]+1]++] = SA[i];
			}
			memcpy(SA,tmpSA,sizeof(int)*n);
			memset(sum,0,sizeof(int)*(maxKey+2));
		}
		int convert(int x){
			if(x<cnt1)return x*3+1;
			return (x-cnt1-1)*3+2;
		}
		int co_convert(int x){
			if(x%3==1)return x/3;
			return x/3+cnt1+1;
		}
		bool compare(int i,int j,int* nextRank){
			if(rank[i]!=rank[j])return rank[i]<rank[j];
			if(i%3+j%3==3)return nextRank[co_convert(i)]<nextRank[co_convert(j)];
			return compare(i+1,j+1,nextRank);
		}
		bool operator ()(int a,int b){
			if(a==b)return false;
			while(rank[a]==rank[b])++a,++b;
			return rank[a]<rank[b];
		}
		void solve(){
			for(int i=0;i<n;i++)
				SA[i]=i;
			if(n<=100){
				sort(SA,SA+n,*this);
				for(int i=0;i<n;i++)
					rank[SA[i]]=i;
				return;
			}
			radixSort(rank+2,SA,n);
			radixSort(rank+1,SA,n);
			radixSort(rank,SA,n);
			tmpRank[SA[0]]=0;
			for(int i=1;i<n;i++)
				tmpRank[SA[i]]=tmpRank[SA[i-1]]+
					(rank[SA[i]]!=rank[SA[i-1]]||
					 rank[SA[i]+1]!=rank[SA[i-1]+1]||
					 rank[SA[i]+2]!=rank[SA[i-1]+2]);
			memcpy(rank,tmpRank,sizeof(int)*n);
			if(rank[SA[n-1]]==n-1)return;
			int* nextRank=rank+n+2;
			int nextN=0;
			cnt1=cnt2=0;
			for(int i=1;i<n;i+=3){
				nextRank[nextN++]=rank[i]+1;
				cnt1++;
			}
			nextRank[nextN++]=0;
			for(int i=2;i<n;i+=3){
				nextRank[nextN++]=rank[i]+1;
				cnt2++;
			}
			cnt0=n-cnt1-cnt2;
			int* nextSA=SA+n;
			DC3 next(nextRank,nextSA,nextN);
			next.solve();
			for(int i=0;i<nextN;i++){
				if(nextRank[i]==0)continue;
				tmpRank[convert(i)]=nextRank[i];
			}
			for(int i=0;i<n;i+=3)
				SA[i/3]=i;
			radixSort(tmpRank+1,SA,cnt0);
			radixSort(rank,SA,cnt0);
			memcpy(tmpSA,SA,sizeof(int)*cnt0);
			for(int i=1,j=0,cnt=0;i<=nextN;i++){
				while(j<cnt0&&(i==nextN||compare(tmpSA[j],convert(nextSA[i]),nextRank))){
					SA[cnt++]=tmpSA[j++];
				}
				SA[cnt++]=convert(nextSA[i]);
			}
			for(int i=0;i<n;i++)
				rank[SA[i]]=i;
		}
};
int DC3::sum[MAXN]={};
int DC3::tmpSA[MAXN];
int DC3::tmpRank[MAXN];

int rank[3*MAXN],SA[3*MAXN],h[MAXN];
char ch[MAXN];

int st[MAXN];
int len[MAXN];
int half[MAXN];
int rmq[MAXN][20];
void build_rmq(int L){
	half[0]=0;
	for(int i=1;i<=L;i++){
		half[i]=half[i-1];
		if((2<<half[i])==i)half[i]++;
	}
	for(int i=0;i<L;i++){
		rmq[i][0]=h[SA[i]];
	}
	for(int r=1;r<20;r++){
		for(int i=0;i+(1<<r)<=L;i++)
			rmq[i][r]=min(rmq[i][r-1],rmq[i+(1<<(r-1))][r-1]);
	}
}
int query(int fr,int to){
	if(fr==to)return 987654321;
	int L=half[to-fr];
	fr++;
	return min(rmq[fr][L],rmq[to-(1<<L)+1][L]);
}
int main(){
	int n,L=0;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%s",ch+L);
		st[i]=L;
		len[i]=strlen(ch+L);
		L+=len[i]+1;
		ch[L-1]='a'-1;
	}
	DC3 dc3=DC3(rank,SA,L,ch);
	dc3.solve();
	dc3.getH(h);
	build_rmq(L);
	for(int i=0;i<n;i++){
		int x=rank[st[i]];
		int fr=0,to=L-1;
		int tmp=x;
		while(tmp-fr>1){
			int mid=(tmp+fr)/2;
			if(query(mid,x)>=len[i])tmp=mid;
			else fr=mid;
		}
		if(query(x,to)>=len[i])to++;
		else {
			tmp=x;
			while(to-tmp>1){
				int mid=(tmp+to)/2;
				if(query(x,mid)>=len[i])tmp=mid;
				else to=mid;
			}
		}
		printf("%d\n",to-fr-1);
	}
}

附上ac自动机模板

#include<bits/stdc++.h> 
using namespace std;

const int maxn=1000010; 
const int maxm=50*10010; 
char t[60],s[maxn]; 
int n; 
int ch[maxm][26];  //Trie树节点  
int val[maxm];     //每个字符串的结尾节点都有一个非0的val  
int fail[maxm];    //前缀指针,fail[i]表示i的前缀指针 
int last[maxm];    //last[i]=j,j节点表示的单词是i节点单词的后缀,且j节点是单词节点  
int sz;            //节点编号 
void insert(char *s)  //构建Trie树  
{ 
    int u=0; 
    int n=strlen(s); 
    for(int i=0;i<n;i++) 
    { 
        int c=s[i]-'a';  //把a..z转为0..25 
        if(!ch[u][c]) 
        { 
            memset(ch[sz],0,sizeof(ch[sz])); 
            val[sz]=0; 
            ch[u][c]=sz++; 
        } 
        u=ch[u][c]; 
    } 
    val[u]++;         //val[u]表示节点0~节点u构成的单词数量 
} 
void getfail()  //计算前缀指针指向v  
{ 
    queue<int> q;           //普通队列 
    fail[0]=0;              //根 
    int u=0; 
    for(int i=0;i<26;i++)   //根的26个节点的前缀指针都指向根,并入队 
    { 
        u=ch[0][i]; 
        if(u) 
    	{ 
      		q.push(u);      //入队 
      		fail[u]=0; 
      		last[u]=0; 
    	} 
	} 
	while(!q.empty()) //广搜计算fail  
    { 
        int r=q.front();q.pop(); //队首r出队 
        for(int i=0;i<26;i++)    //枚举r的26个子节点u,求fail[u] 
        { 
            u=ch[r][i]; 
            if(!u)                      //如果u不存在,则跳向其父节点r前缀指针指向的第i个子节点 
			{ 
				ch[r][i]=ch[fail[r]][i]; 
				continue;          //继续枚举r的下一个子节点 
			} 
            q.push(u);              //如果u存在,则入队 
            int v=fail[r]; 
            while(v&&!ch[v][i]) v=fail[v]; //v存在并且v没有第i个子节点,则跳到v的前缀指针指向的节点 
            fail[u]=ch[v][i];          //v存在并且v的第i个子节点也存在,就可以确定前缀指针 
            last[u]=val[fail[u]]?fail[u]:last[fail[u]];  
        }      //fail[u]是一个完整单词且是u的后缀        否则 
    } 
}
int find(char *s)          //在s中查找出现了哪几个模板的单词  
{ 
    int u=0,cnt=0;         //从根开始,cnt为答案 
    int n=strlen(s); 
    for(int i=0;i<n;i++)   //扫描文章中的每个字符, 
    { 
        int c=s[i]-'a';    //把a..z转为0..25 
        u=ch[u][c]; 
        int temp=0;        //必须赋初值为0,否则如果下面两个判断都不成立,while也可正常执行 
        if(val[u])         //如果u是一个完整单词 
            temp=u; 
        else if(last[u])    //如果u的后缀last[u]存在 
				temp=last[u]; 
        while(temp) 
        { 
            cnt+=val[temp];  //累加单词数量 
            val[temp]=0;     //标记,加过了不能再加 
            temp=last[temp]; //跳到当前temp的后缀(比temp短),更新temp 
        } 
    } 
    return cnt; 
} 
int main() 
{ 
    //freopen("ks.in","r",stdin); 
    //freopen("ks.out","w",stdout);        
    memset(ch[0],0,sizeof(ch[0])); //初始化0号节点的相关信息(多组数据,每次需要初始化)  
	memset(last,0,sizeof(last)); 
    sz=1;   
    scanf("%d",&n);        //读入n个单词 
    for(int i=1;i<=n;i++)  //构建Trie树  
    { 
        scanf("%s",t); 
        insert(t);     
    } 
    getfail();             //计算前缀指针 
    scanf("%s",s);         //读入文章 
    int ans=find(s);       //查找  
    printf("%d\n",ans); 
    return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值