省選模擬賽Round2Day2 Endless 圖 Light

 

image

image image

 

題解:

尋找長度爲2len的平方串有一個技巧

在len,2len,3len....位置處設置一個關鍵點

求出相鄰的兩個關鍵點的LCP與LCS

如果|LCP|+|LCS|-1>=len

就說明這一部分存在|LCP|-|LCS|-len個平方串

從細黑線到細藍線爲起點的所有長度爲2len的串都是平方串

找到了所有平方串,剩下的就是一個倍增並查集的裸題了

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 300005
#define LOG 19
#define LL long long
const int mod1=998244353;
const int mod2=1000000009;
int n;
int pw1[N],pw2[N],hh1[N],hh2[N];
int gethh1(int l,int r){return (1ll*hh1[r]+1ll*mod1-1ll*hh1[l-1]*pw1[r-l+1]%mod1)%mod1;}
int gethh2(int l,int r){return (1ll*hh2[r]+1ll*mod2-1ll*hh2[l-1]*pw2[r-l+1]%mod2)%mod2;}
int LCP(int x,int y)
{
	int l=0,r=min(y-x,n-y+1),mid;
	while(l<r){
		mid=(l+r+1)>>1;
		if(gethh1(x,x+mid-1)==gethh1(y,y+mid-1)&&gethh2(x,x+mid-1)==gethh2(y,y+mid-1))
			l=mid;
		else r=mid-1;
	}
	return l;
}
int LCS(int x,int y)
{
	int l=0,r=y-x,mid;
	while(l<r){
		mid=(l+r+1)>>1;
		if(gethh1(x-mid+1,x)==gethh1(y-mid+1,y)&&gethh2(x-mid+1,x)==gethh2(y-mid+1,y))
			l=mid;
		else r=mid-1;
	}
	return l;
}
int w[N],id[N],a[N],fa[LOG+2][N];
bool cmp(int x,int y){return w[x]<w[y];}
int find(int k,int x){return x==fa[k][x]?x:fa[k][x]=find(k,fa[k][x]);}
LL ans;int ens,now;
void merge(int k,int x,int y)
{
	int p=find(k,x),q=find(k,y);
	if(p==q)return;
	fa[k][p]=q;
	if(k==0){ans+=now;ens++;return;}
	merge(k-1,x,y);merge(k-1,x+(1<<(k-1)),y+(1<<(k-1)));
}
int lg[N];
int main()
{
	freopen("endless.in","r",stdin);
	freopen("endless.out","w",stdout);
	int T,i,j,k;
	T=gi();pw1[0]=pw2[0]=1;lg[0]=-1;
	while(T--){
		n=gi();ans=0;ens=0;
		for(i=1;i<=n;i++){
			a[i]=gi();lg[i]=lg[i>>1]+1;
			for(j=0;j<=LOG;j++)fa[j][i]=i;
			hh1[i]=(1ll*hh1[i-1]*(n+1)+1ll*a[i])%mod1;
			hh2[i]=(1ll*hh2[i-1]*(n+1)+1ll*a[i])%mod2;
			pw1[i]=1ll*pw1[i-1]*(n+1)%mod1;
			pw2[i]=1ll*pw2[i-1]*(n+1)%mod2;
		}
		for(i=1;i<=(n>>1);i++)w[i]=gi(),id[i]=i;
		sort(id+1,id+(n>>1)+1,cmp);
		
		for(i=1;i<=(n>>1)&&ens<n-1;i++){
			int len=id[i];now=w[len];
			for(j=len;j+len<=n&&ens<n-1;j+=len){
				int l=LCS(j,j+len);
				int r=LCP(j,j+len);
				if(l+r-1>=len){
					k=lg[l+r-1];
					merge(k,j-l+1,j-l+1+len);
					merge(k,j+r-(1<<k),j+r-(1<<k)+len);
				}
			}
		}
		printf("%lld\n",ans);
	}
}

 

 

 

 

 

image

 

image
image

 

 

 

題解:

發現set中的swap函數在開C++11的情況下是O(1)的,不開就是O(n)的

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 1000005
set<int> S[N];
set<int>::iterator it;
int d[N];
const int mod=998244353;
int main()
{
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	int n,m,i,u,v;
	n=gi();m=gi();
	for(i=1;i<=m;i++){
		u=gi();v=gi();
		if(u>v)swap(u,v);
		S[u].insert(v);
	}
	for(i=1;i<=n;i++){
		d[i]=S[i].size();
		int tmp=*S[i].begin();
		S[i].erase(tmp);
		if(S[tmp].size()<S[i].size())
			S[tmp].swap(S[i]);
		for(it=S[i].begin();it!=S[i].end();it++)
			S[tmp].insert(*it);
	}
	int ans=1;
	for(i=1;i<=n;i++)
		ans=1ll*ans*(n-d[i])%mod;
	printf("%d\n",ans);
}

 

 

 

 

image image image image

 

題解:看不太懂

佔坑不填

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章