[Hash 倍增Floyd] BZOJ 2085 [Poi2010]Hamsters

Po姐的题解:http://blog.csdn.net/popoqqq/article/details/44077515

搬运下复杂度分析吧


这不会T?

首先设第i个字符串的长度为ai,设k=Σai

易知当计算f[i][j]时的复杂度是O(min(ai,aj))

那么现在的问题就是当k固定时,最大化ΣΣmin(ai,aj)

我们将所有的ai排个序,容易发现当相邻的两个数ai和aj都变为(ai+aj)/2时目标函数一定会增大

证明:

若ak<=ai<aj,那么min(ak,ai)和min(ak,aj)都不变
若ai<aj<=ak,那么min(ai,ak)+min(aj,ak)=ai+aj一定不变

min(ai,ai)+min(aj,aj)=ai+aj也不变

只有min(ai,aj)增大了

因此最终当所有的ai都相同时目标函数最大

故每个ai都等于k/n,这一步的最终时间复杂度是O(k/n*n^2)=O(kn)

k=10W,n=200,显然不会T


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline int read(char *s)
{
	char c=nc();int len=0;
	for (;!(c>='a' && c<='z');c=nc());
	for (;c>='a' && c<='z';s[++len]=c,c=nc()); s[++len]=0; return len-1;
}

const int N=205;
ll f[N][N],h[N][N],tmp[N][N];
ll ans=1LL<<60;
int Len,n,m;
char S[200005],str[200005];
int st[N],ed[N],len[N];

const ll P=1000000007,X=1234567;
ll H[200005],iX[200005];

inline void Pre()
{
	iX[0]=1;
	for (int i=1;i<=Len;i++)
		(iX[i]=iX[i-1]*X)%=P;
	for (int i=Len;i;i--)
		(H[i]=H[i+1]*X+S[i]-'a')%=P;
}

inline ll Get(int l,int r){
	return ((H[l]-H[r+1]*iX[r-l+1])%P+P)%P;
}

inline ll Get(int x,int l,int r){
	return Get(st[x]+l-1,st[x]+r-1);
}

inline int Calc(int x,int y){
	for (int i=min(len[x],len[y])-(len[y]<=len[x]);~i;i--)
		if (Get(x,len[x]-i+1,len[x])==Get(y,1,i))
			return len[y]-i;
	return len[y];
}

int main()
{
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(m); m--;
	for (int i=1;i<=n;i++) 
	{
		len[i]=read(str); st[i]=ed[i-1]+1; ed[i]=st[i]+len[i]-1;
		for (int j=1;j<=len[i];j++) S[++Len]=str[j];
	}
	Pre();
	memset(f,0x3f,sizeof(f));
	memset(h,0x3f,sizeof(h));
	for (int i=1;i<=n;i++) 
		h[i][i]=0;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			f[i][j]=Calc(i,j);
	for (int t=0;(1<<t)<=m;t++)
	{
		if (m&(1<<t))
		{
			memset(tmp,0x3f,sizeof(tmp));
			for (int k=1;k<=n;k++)
				for (int i=1;i<=n;i++)
					for (int j=1;j<=n;j++)
						tmp[i][j]=min(tmp[i][j],h[i][k]+f[k][j]);
			memcpy(h,tmp,sizeof(tmp));
		}
		memset(tmp,0x3f,sizeof(tmp));
		for (int k=1;k<=n;k++)
			for (int i=1;i<=n;i++)
				for (int j=1;j<=n;j++)
					tmp[i][j]=min(tmp[i][j],f[i][k]+f[k][j]);
		memcpy(f,tmp,sizeof(tmp));
	}
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			ans=min(ans,len[i]+h[i][j]);
	printf("%lld\n",ans);
	return 0;
}



你可能感兴趣的:([Hash 倍增Floyd] BZOJ 2085 [Poi2010]Hamsters)