zoukankan      html  css  js  c++  java
  • BZOJ 2085 luogu P3502 [POI2010]Hamsters (KMP、Floyd、倍增)

    数组开小毁一生……

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2085

    这题在洛谷上有个条件是“互不包含”,其实bzoj的数据也满足这个条件,否则我目前已知的所有做法都是错的。

    个人觉得AC自动机可以用其他办法做,但是没试过

    KMP(或者hash), (f[i][j])表示(i)完了接上(j)需要多少个字符,直接用KMP求出最长的同时是(j)串的前缀和(i)串的后缀的串即可

    然后求走((m-1))步的最短路,倍增Floyd

    并不是多串匹配一定要用AC自动机!即使不考虑正确性,AC自动机的Trie树在复杂度上可能还多个字符集大小,不一定比KMP快,一定要合理选择!

    代码

    KMP:

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #define llong long long
    using namespace std;
    
    const int N = 200;
    const int S = 26;
    const int L = 1e5+1e3;
    const int LGM = 30;
    const llong INF = 1e17;
    llong f[N+3][N+3],g[N+3][N+3],g0[N+3][N+3];
    char a[L+3];
    int nxt[L+3];
    int len[L+3];
    int slen[L+3];
    int n; llong m;
    
    void update(llong &x,llong y) {x = min(x,y);}
    
    int KMP(char str1[],char str2[],int len1,int len2)
    {
    	for(int i=0; i<=len1; i++) nxt[i] = 0;
    	for(int i=2; i<=len1; i++)
    	{
    		nxt[i] = nxt[i-1];
    		while(nxt[i]!=0 && str1[i]!=str1[nxt[i]+1])
    		{
    			nxt[i] = nxt[nxt[i]];
    		}
    		if(str1[i]==str1[nxt[i]+1]) nxt[i]++;
    	}
    	if(str1==str2)
    	{
    		return len1-nxt[len1];
    	}
    	else
    	{
    		int j = 0;
    		for(int i=1; i<=len2; i++)
    		{
    			while(j && str1[j+1]!=str2[i])
    			{
    				j = nxt[j];
    			}
    			if(j<len1 && str1[j+1]==str2[i]) j++;
    		}
    		return len1-j;
    	}
    }
    
    int main()
    {
    	scanf("%d%lld",&n,&m);
    	for(int i=1; i<=n; i++)
    	{
    		scanf("%s",a+slen[i-1]+1); len[i] = strlen(a+slen[i-1]+1); slen[i] = slen[i-1]+len[i]+1; a[slen[i]] = ' ';
    	}
    	for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) {f[i][j] = g0[i][j] = g[i][j] = INF;}}
    	for(int i=1; i<=n; i++) f[i][i] = len[i];
    	for(int i=1; i<=n; i++)
    	{
    		for(int j=1; j<=n; j++)
    		{
    			g0[j][i] = KMP(a+slen[i-1],a+slen[j-1],len[i],len[j]);
    		}
    	}
    	/*
    	for(int i=1; i<=n; i++)
    	{
    		for(int j=1; j<=n; j++)
    		{
    			printf("g0: %d %d %lld
    ",i,j,g0[i][j]);
    		}
    	}
    	*/
    	m--;
    	while(m>0)
    	{
    		if(m&1)
    		{
    			for(int k=1; k<=n; k++)
    			{
    				for(int i=1; i<=n; i++)
    				{
    					for(int j=1; j<=n; j++)
    					{
    						update(g[i][j],f[i][k]+g0[k][j]);
    					}
    				}
    			}
    			for(int i=1; i<=n; i++)
    			{
    				for(int j=1; j<=n; j++)
    				{
    					f[i][j] = g[i][j];
    					g[i][j] = INF;
    				}
    			}
    		}
    		for(int k=1; k<=n; k++)
    		{
    			for(int i=1; i<=n; i++)
    			{
    				for(int j=1; j<=n; j++)
    				{
    					update(g[i][j],g0[i][k]+g0[k][j]);
    				}
    			}
    		}
    		for(int i=1; i<=n; i++)
    		{
    			for(int j=1; j<=n; j++)
    			{
    				g0[i][j] = g[i][j];
    				g[i][j] = INF;
    			}
    		}
    		m>>=1;
    	}
    	llong ans = INF;
    	for(int i=1; i<=n; i++)
    	{
    		for(int j=1; j<=n; j++)
    		{
    			ans = min(ans,f[i][j]);
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    AC自动机WA+TLE代码

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<vector>
    #define llong long long
    using namespace std;
    
    const int N = 200;
    const int S = 26;
    const int L = 1e5+1;
    const int LGM = 30;
    const llong INF = 1e17;
    void update(llong &x,llong y) {x = min(x,y);}
    llong g0[N+3][N+3],g[N+3][N+3],f[N+3][N+3];
    int len[N+3];
    int fail[L+3];
    int son[L+3][S+3];
    int idpos[N+3];
    char a[L+3];
    int id[L+3];
    int que[L+3];
    int dep[L+3];
    int n,rtn,siz; llong m;
    
    void insertstr(char str[],int sid)
    {
    	int u = rtn;
    	for(int i=1; i<=len[sid]; i++)
    	{
    		if(son[u][str[i]])
    		{
    			u = son[u][str[i]];
    		}
    		else
    		{
    			siz++; son[u][str[i]] = siz;
    			u = siz;
    		}
    	}
    	id[u] = sid;
    	idpos[sid] = u;
    }
    
    void add(int u,int v,llong w)
    {
    	update(g0[id[u]][id[v]],w);
    }
    
    void getfail()
    {
    	int head = 1,tail = 0;
    	for(int i=1; i<=S; i++)
    	{
    		int v = son[rtn][i];
    		if(v)
    		{
    			tail++; que[tail] = v;
    			fail[v] = rtn;
    		}
    	}
    	while(head<=tail)
    	{
    		int u = que[head]; head++;
    		for(int i=1; i<=S; i++)
    		{
    			int v = son[u][i];
    			if(v) {fail[son[u][i]] = son[fail[u]][i]; tail++; que[tail] = v;}
    			else {son[u][i] = son[fail[u]][i];}
    		}
    	}
    }
    
    void bfs(int s)
    {
    	printf("bfs(%d)
    ",s);
    	for(int i=1; i<=siz; i++) dep[i] = 0;
    	int head = 1,tail = 1; que[1] = s;
    	while(head<=tail)
    	{
    		int u = que[head]; head++;
    		int v = fail[i];
    		for(int i=1; i<=S; i++)
    		{
    			v = son[u][i];
    			if(v && dep[v]==0)
    			{
    				dep[v] = dep[u]+1;
    				add(s,v,dep[v]);
    				tail++; que[tail] = v;
    			}
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%lld",&n,&m); rtn = siz = 0;
    	for(int i=1; i<=n; i++)
    	{
    		scanf("%s",a+1); len[i] = strlen(a+1);
    		for(int j=1; j<=len[i]; j++) a[j] -= 96;
    		insertstr(a,i);
    	}
    	getfail();
    	for(int i=0; i<=siz; i++) printf("AC%d fail%d
    ",i,fail[i]);
    	for(int i=0; i<=siz; i++) {for(int j=1; j<=S; j++) {if(son[i][j]) {printf("son[%d][%c]=%d
    ",i,j+96,son[i][j]);}}}
    	for(int i=1; i<=n; i++) {for(int j=1; j<=n; j++) {f[i][j] = g0[i][j] = g[i][j] = INF;}}
    	for(int i=1; i<=n; i++) f[i][i] = 0ll;
    	for(int i=1; i<=siz; i++)
    	{
    		if(id[i])
    		{
    			bfs(i);
    		}
    	}
    	/*
    	for(int i=1; i<=n; i++)
    	{
    		for(int j=1; j<=n; j++)
    		{
    			printf("g0: %d %d %lld
    ",i,j,g0[i][j]);
    		}
    	}
    	*/
    	m--;
    	while(m>0)
    	{
    		if(m&1)
    		{
    			for(int k=1; k<=n; k++)
    			{
    				for(int i=1; i<=n; i++)
    				{
    					for(int j=1; j<=n; j++)
    					{
    						update(g[i][j],f[i][k]+g0[k][j]);
    					}
    				}
    			}
    			for(int i=1; i<=n; i++)
    			{
    				for(int j=1; j<=n; j++)
    				{
    					f[i][j] = g[i][j];
    					g[i][j] = INF;
    				}
    			}
    		}
    		for(int k=1; k<=n; k++)
    		{
    			for(int i=1; i<=n; i++)
    			{
    				for(int j=1; j<=n; j++)
    				{
    					update(g[i][j],g0[i][k]+g0[k][j]);
    				}
    			}
    		}
    		for(int i=1; i<=n; i++)
    		{
    			for(int j=1; j<=n; j++)
    			{
    				g0[i][j] = g[i][j];
    				g[i][j] = INF;
    			}
    		}
    		m>>=1;
    	}
    	llong ans = INF;
    	for(int i=1; i<=n; i++)
    	{
    		for(int j=1; j<=n; j++)
    		{
    			ans = min(ans,len[i]+f[i][j]);
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    /*
    4 11
    aaaaaaa
    aaaa
    aaaaaa
    aaaaaaaaaa
    */
    
  • 相关阅读:
    盒模型新增样式
    css3 文字处理
    popupWindow的用法(1)
    spinner适配器
    layer-list解决listView中相邻item之间线的重叠的问题
    安卓中常用的shape,selector,layer-list
    Pagerstwich tab样式加下拉刷新(三)
    PagerSwitch tab样式加下拉刷新(二)
    PagerSwitch tab样式加上下拉刷新(一)
    listview中textview响应部分文本点击事件
  • 原文地址:https://www.cnblogs.com/suncongbo/p/11038876.html
Copyright © 2011-2022 走看看