zoukankan      html  css  js  c++  java
  • test20181020 B君的第二题

    B君的第二题

    1
    2

    分析

    题目就是让你求文本框与s匹配到了哪个位置。

    考场70分

    一看就是裸的kmp,直接打上去。

    const int MAXN=1e5+8;
    char s[MAXN],t[MAXN];
    int n,m;
    int nx[MAXN];
    int f[MAXN],len;
    
    int main()
    {
      freopen("xining.in","r",stdin);
      freopen("xining.out","w",stdout);
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	scanf("%s",t+1);
    	m=strlen(t+1);
    	
    	for(int i=2;i<=n;++i)
    	{
    		int p=nx[i-1];
    		while(p&&s[p+1]!=s[i])
    			p=nx[p];
    		if(s[p+1]==s[i])
    			++p;
    		nx[i]=p;
    	}
    	
    	printf("%d
    ",n);
    	for(int i=1;i<=m;++i)
    	{
    		if(t[i]=='-')
    		{
    			--len;
    			if(len<0)
    				len=0;
    			printf("%d
    ",n-f[len]);
    			continue;
    		}
    //		cerr<<"pro "<<i<<endl;
    		int p=f[len];
    //		cerr<<" p="<<p<<endl;
    		while(p&&s[p+1]!=t[i])
    			p=nx[p];
    		if(s[p+1]==t[i])
    			++p;
    		f[++len]=p;
    //		cerr<<" p="<<p<<endl;
    		printf("%d
    ",n-p);
    	}
    //  fclose(stdin);
    //  fclose(stdout);
        return 0;
    }
    

    结果TLE了。实际上时间复杂度(O(n^2))

    标解

    这道题能卡kmp,是因为往回走后重新匹配跳next时复杂度没了保证。

    退格操作可以让匹配长度剧增,这与kmp要满足长度增加量最多为文本串的长度的性质不符,所以要被卡。

    B君:可以前n/2都是a,然后后面一个-一个b交替出现,就可以把kmp卡成n方的了。

    但是AC自动机中的一个构建优化是把不存在的儿子补齐,所以考虑AC自动机。

    然后因为AC自动机是在Trie图上建的,距离不能直接求,所以要预处理。

    时间复杂度(O(n))

    const int MAXN=1e5+7;
    
    vector<int>a[MAXN];
    int d[MAXN];
    
    const int CHARSET=26;
    struct Trie
    {
    	int sz;
    	int to[MAXN][CHARSET];
    	int nx[MAXN];
    	int fa[MAXN];
    	int v[MAXN];
    	
    	il void ins(rg char*s)
    	{
    		rg int p=0;
    		for(;*s;++s)
    		{
    			rg int c=*s-'a';
    			if(to[p][c]==0)
    			{
    				to[p][c]=++sz;
    				fa[sz]=p;
    			}
    			p=to[p][c];
    		}
    		v[p]=1;
    	}
    	
    	il void build()
    	{
    		rg queue<int>Q;
    		Q.push(0);
    		while(!Q.empty())
    		{
    			rg int x=Q.front();
    			Q.pop();
    			v[x]|=v[nx[x]];
    			for(rg int i=0;i<CHARSET;++i)
    			{
    				if(to[x][i])
    				{
    					nx[to[x][i]]=x?to[nx[x]][i]:0;
    					Q.push(to[x][i]);
    				}
    				else
    				{
    					to[x][i]=x?to[nx[x]][i]:0;
    				}
    			}
    		}
    		for(rg int i=0;i<=sz;++i)
    			for(rg int j=0;j<CHARSET;++j)
    			{
    				a[to[i][j]].push_back(i);
    			}
    		memset(d,0x3f,sizeof d);
    		for(rg int i=0;i<=sz;++i)
    			if(v[i])
    			{
    				Q.push(i);
    				d[i]=0;
    			}
    		while(!Q.empty())
    		{
    			rg int x=Q.front();
    			Q.pop();
    			for(rg int i=0;i<a[x].size();++i)
    			{
    				rg int y=a[x][i];
    				if(d[y]>d[x]+1)
    				{
    					d[y]=d[x]+1;
    					Q.push(y);
    				}
    			}
    		}
    	}
    }T;
    
    char s[MAXN],t[MAXN];
    
    int f[MAXN],len;
    
    int main()
    {
      freopen("xining.in","r",stdin);
      freopen("xining.out","w",stdout);
    	scanf("%s",s);
    	T.ins(s);
    	T.build();
    	scanf("%s",t);
    	printf("%d
    ",d[f[len]]);
    	for(rg int i=0;t[i];++i)
    	{
    		if(t[i]=='-')
    		{
    			if(len>0)
    				--len;
    		}
    		else
    		{
    			rg int x=T.to[f[len]][t[i]-'a']; // edit 1
    			f[++len]=x;
    		}
    //		cerr<<"f="<<f[len]<<endl;
    		printf("%d
    ",d[f[len]]);
    	}
    //  fclose(stdin);
    //  fclose(stdout);
        return 0;
    }
    
    静渊以有谋,疏通而知事。
  • 相关阅读:
    Android的Activity屏幕切换动画(一)-左右滑动切换
    404 Not Found 由来
    HTML+CSS 制作HTML5标志图
    发现 网站错误
    链接指南
    偷懒省事有工具啊
    程序员很穷(转)
    谷歌浏览器修改CSS和js后同步保存到文件中 (译)
    程序员眼睛的保护(爱护眼睛,你我做起)
    仿站违法和侵权吗?
  • 原文地址:https://www.cnblogs.com/autoint/p/9835871.html
Copyright © 2011-2022 走看看