AtCoder Beginner Contest 272 SA_IS算法总结

ABC也很难的好不好。

可能是老年人手速太慢 实力太拉。

先上F 将s和t各复制一倍 就是后缀排序的问题。具体细节是给\(s*2\)后接n个a再接\(2*t\)再接n个z。

可以证明两个有效串至少能比较到a和z。

我用的SA_IS O(n)的常数还行。

分为三个步骤:1 确定LMS的顺序与离散化 2 LMS的后缀排序(递归SA_IS算法 3 最后诱导排序原序列。

最神奇的当属诱导排序与LMS的排序(归纳诱导排序可证正确性

果然是只有神仙才能想出来的神仙算法。

学习经历:翻了10个左右博客 很多文笔虽然很长但是说的也不够清晰或者过于细节导致没有耐心观看。

这里给出两个比较清晰的博客来学习 神仙一 神仙二

当然难度上打不过SAM 但是可以吊打倍增。相比倍增还是最容易理解的了。。

code
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define P 1000000007ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define sq sqrt
#define a(x) t[x].a
#define sum(x) t[x].sum
#define b(x) t[x].b
#define F first
#define S second
#define mod 998244353
#define sc(A) scanf("%d",&A)
#define put(A) printf("%d\n",A);
#define add1(x,y,m) ((x)+(y)>=m?(x)+(y)-(m):(x)+(y))
using namespace std;
const int MAXN=200010,maxn=MAXN*12;
int n,m;
char a[MAXN],b[MAXN];
int x[maxn],y[maxn],h[maxn],c[maxn],sa[maxn],rk[maxn],op[maxn],pos[maxn],c1[maxn];
#define L(x) sa[c[s[x]]--]=x
#define R(x) sa[c[s[x]]++]=x
inline void sa_sort(int *S,int n,int m,int *s,int *op,int tn)//induce sort
{
	rep(1,n,i)sa[i]=0;
	rep(1,m,i)c1[i]=0;
	rep(1,n,i)++c1[s[i]];
	rep(2,m,i)c1[i]+=c1[i-1];
	rep(1,m,i)c[i]=c1[i];
	for(int i=tn;i;--i)L(S[i]);
	rep(1,m,i)c[i]=c1[i-1]+1;
	rep(1,n,i)if(sa[i]>1&&op[sa[i]-1])R(sa[i]-1);
	rep(1,m,i)c[i]=c1[i];
	for(int i=n;i;--i)if(sa[i]>1&&!op[sa[i]-1])L(sa[i]-1);
}
inline void SA_IS(int n,int m,int *s,int *op,int *pos)
{
	int tot=0,cnt=0;int *S=s+n;
	op[n]=0;
	for(int i=n-1;i;--i)op[i]=(s[i]!=s[i+1])?s[i]>s[i+1]:op[i+1];
	//1 是 L型 0是 S型
	rk[1]=0;
	rep(2,n,i)if(op[i-1]&&!op[i])pos[++tot]=i,rk[i]=tot;
	else rk[i]=0;
	sa_sort(pos,n,m,s,op,tot);
	int u=0,p=0;
	rep(1,n,i)if(rk[sa[i]])
	{
		u=rk[sa[i]];
		if(cnt<=1||pos[u+1]-pos[u]!=pos[p+1]-pos[p])++cnt;
		else
		{
			rep(0,pos[u+1]-pos[u],j)
			if(s[pos[u]+j]!=s[pos[p]+j]||op[pos[u]+j]!=op[pos[p]+j]){++cnt;break;}
		}
		S[u]=cnt;p=u;
	}
	if(tot!=cnt)SA_IS(tot,cnt,S,op+n,pos+n);
	else rep(1,tot,i)sa[S[i]]=i;
	rep(1,tot,i)S[i]=pos[sa[i]];
	sa_sort(S,n,m,s,op,tot);
}
int main()
{
	//freopen("1.in","r",stdin);
	sc(n);scanf("%s",a+1);
	scanf("%s",b+1);
	/*n=4;x[1]=2;x[2]=2;x[3]=2;x[4]=1;
	SA_IS(n--,27,x,op,pos);
	cout<<sa[1]<<' '<<sa[2]<<' '<<sa[3]<<' '<<sa[4]<<endl;*/
	rep(1,n,i)x[i]=x[i+n]=a[i]-'a'+2,x[i+n+n]=2;
	rep(1,n,i)x[i+n*3]=x[i+n*4]=b[i]-'a'+2,x[i+n*5]=27;
	n=n*6;x[++n]=1;SA_IS(n--,27,x,op,pos);
	//rep(1,n,i)cout<<sa[i]<<' '<<endl;
	n/=6;
	ll ans=0,cnt=0;
	for(int i=n*6+1;i>=1;--i)
	{
		if(sa[i]<=n)ans+=cnt;
		if(sa[i]>=3*n+1&&sa[i]<=4*n)++cnt;
	}
	printf("%lld\n",ans);
	return 0;
}

D 题是个一个广搜的题 提前预处理出来能走的方式 正常广搜即可 复杂度是线性的。

code
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define P 1000000007ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define sq sqrt
#define a(x) t[x].a
#define sum(x) t[x].sum
#define b(x) t[x].b
#define F first
#define S second
#define mod 998244353
using namespace std;
char *fs,*ft,buf[1<<15];
inline char gc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    return x*f;
}
const int MAXN=200010,maxn=410;
int n,m,cnt,h,t;
int b[MAXN];
int vis[maxn][maxn];
struct wy
{
	int a,b;
}s[MAXN],q[MAXN];
int dx[5]={0,1,1,-1,-1};
int dy[5]={0,1,-1,1,-1};
inline void bfs()
{
	while(++h<=t)
	{
		wy w=q[h];
		for(int i=1;i<=cnt;++i)
		{
			rep(1,4,j)
			{
				int w1=w.a+s[i].a*dx[j];
				int w2=w.b+s[i].b*dy[j];
				if(w1<1||w2<1||w1>n||w2>n)continue;
				if(vis[w1][w2]!=-1)continue;
				vis[w1][w2]=vis[w.a][w.b]+1;
				q[++t]=(wy){w1,w2};
			}
		}
	}
}
int main()
{
	//freopen("1.in","r",stdin);
	memset(vis,-1,sizeof(vis));
	n=read();m=read();
	rep(1,400,i)b[i*i]=i;
	rep(0,400,i)
	{
		int res=m-i*i;
		if(res==0)s[++cnt]=(wy){i,0};
		if(res<0)continue;
		if(res>400*400)continue;
		if(b[res]==0)continue;
		s[++cnt]=(wy){i,b[res]};
	}
	vis[1][1]=0;q[++t]=(wy){1,1};
	bfs();
	rep(1,n,i)
	{
		rep(1,n,j)printf("%d ",vis[i][j]);
		puts("");
	}
	return 0;
}

E 每个时刻序列中每个数字都会加上i 求M个时刻中每个时刻序列中的MEX值(即最小没有出现的非负数。

一个数字有贡献当且紧当为正数 有答案的上界为n 某个位置i上的数字从开始有可能有贡献到没有任何贡献次数为\(\frac{n}{i}\)

把这些有限的次数都找到枚举某一次时放出来即可。可以使用vector使得时间复杂度为nln(n) 也可以直接sort多一个log

code
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define P 1000000007ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define sq sqrt
#define a(x) t[x].a
#define sum(x) t[x].sum
#define b(x) t[x].b
#define F first
#define S second
#define mod 998244353
using namespace std;
char *fs,*ft,buf[1<<15];
inline char gc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    return x*f;
}
const int MAXN=2000010,maxn=410;
int n,m;
struct wy
{
	int a,b;
}s[8000010];
int f[MAXN];
inline int cmp(wy a,wy b){return a.b<b.b;}
int main()
{
//	freopen("1.in","r",stdin);
	n=read();m=read();
	int cnt=0;
	rep(1,n,i)
	{
		int x=read();
		if(x>=0)
		{
			rep(1,m/i+1,j)s[++cnt]=(wy){x+i*(j-1),j-1};
		}
		else
		{
			int ww=(-x-1)/i+1;
			if(ww>m)continue;
			x=x+ww*i;
			rep(1,m/i+1,j)s[++cnt]=(wy){x+i*(j-1),ww+j-1};
		}
	}
	sort(s+1,s+1+cnt,cmp);
	int ww=0;
	rep(1,m,i)
	{
		int last=ww;
		while(s[ww+1].b<=i&&ww+1<=cnt)++ww;
		rep(last+1,ww,j)if(s[j].a<=2000000)f[s[j].a]=1;
		int j=0;
		while(f[j])++j;
		printf("%d\n",j);
		rep(last+1,ww,j)if(s[j].a<=2000000)f[s[j].a]=0;
	}
	return 0;
}

G 找到一个数字M(M>2) 使得\(a_i%M\)后的数字在序列中为绝对众数。

容易想到如果某个M合法那么P|M P应该也是合法的。当然P!=2.当M为2的整数次幂的时候可以使用4来代替。

这个绝对众数可以联想到摩尔根投票法。直接是很难用的。

但是可以注意到如果已知\(a_i,a_j\)入选 那么只需要找到\(a_i-a_j\)里的质因子判断 每个数字减去\(a_i\)即可。

利用摩尔根投票法 即入选数字大于一半。

这里有两种做法 一种是观察到n位偶数那么至少有两个数相邻 依次check复杂度为 \(n\cdot sqrt(A) \cdot w\)w为质因子个数。

n为奇数只有一类极端情况不满足 可以交换\(a_1,a_2\)一下再做一遍。在n很大的时候做一遍即可。

另外一种是 每次随机找\(a_i,a_j\) 每次找对的概率为\(\frac{1}{4}\) 做个20次 没找对的概率为\((\frac{3}{4})^{20}\)

非常小 这样复杂度为\(20*sqrt(A)+20*n*w\) 非常巧妙。

code
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define P 1000000007ll
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define sq sqrt
#define a(x) t[x].a
#define sum(x) t[x].sum
#define b(x) t[x].b
#define F first
#define S second
#define mod 998244353
#define add(x,y,m) ((x)+(y)>=m?(x)+(y)-(m):(x)+(y))
using namespace std;
const int MAXN=5010,maxn=410;
int n,ans,cnt;
int a[MAXN];
int q[MAXN];
inline void check(int ww,int pos)
{
	cnt=0;
	if(ww%4==0)q[++cnt]=4;
	while(ww%2==0)ww/=2;
	for(int i=3;i*i<=ww;++i)
	{
		if(ww%i==0)
		{
			q[++cnt]=i;
			while(ww%i==0)ww/=i;
		}
	}
	if(ww>1)q[++cnt]=ww;
	rep(1,cnt,j)
	{
		int cc=0;
		rep(1,n,i)
		{
			if((a[i]-a[pos])%q[j]==0)++cc;
		}
		if(cc*2>n){ans=q[j];return;}
	}
}
int main()
{
	//freopen("1.in","r",stdin);
	srand(time(0));
	scanf("%d",&n);
	rep(1,n,i)scanf("%d",&a[i]);
	int k=1;
	while(k<=20)
	{
		int w1=rand()%n+1;
		int w2=rand()%n+1;
		while(w1==w2)w2=rand()%n+1;
		int ww=abs(a[w1]-a[w2]);
		check(ww,w1);
		if(ans){printf("%d\n",ans);return 0;}
		++k;
	}
	puts("-1");
	return 0;
}
posted @ 2022-10-12 23:38  chdy  阅读(173)  评论(0编辑  收藏  举报