題解:
尋找長度爲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);
}
}
題解:
發現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);
}
題解:看不太懂
佔坑不填