arc141 vp 记录

水平下滑到这个地步了吗/kk

赛时 AB,赛后 C

A - Periodic Number

B - Increasing Prefix XOR

发现每次我都至少要比上一个高一位,直接 \(dp\) 即可。

C - Bracket and Permutation

对于一个合法串,\(P\) 中一定是一段连续的,这时通过 \(Q\) 确定;否则直接由 \(P\) 确定即可。

D - Non-divisible Set

啊这,才发现把题看错了。就离谱,对着错题意想了不知道多久,关键是错题意还弱化了/ll

有个经典构造:对于每个奇数 \(i\) 构造抽屉 \(\{2^ki\}\)。然后 wlq 说就是套路的了,实在不明白。

observation: 若有 \(2^ab|2^cd\),则必须 \(b|d,a\leqslant c\),即对于所有的 \(a|b\)\(a\) 集合的 \(2\) 的幂次必须大于 \(b\) 集合。

可以发现只要满足这些条件,它在一定的范围内是可以浮动的。于是我们可以贪心求出最小和最大值,简单判断即可。

一个构造是,前面都取最大,中间取要求的值,后面都取最小,容易发现这样是适配的。

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e6+10;
const int mod=1e9+7;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int n,m,a[maxn],vis[maxn],l[maxn],r[maxn];
int main(){
	n=read(),m=read()*2;
	for(int i=1;i<=n;i++)a[i]=read(),vis[a[i]]=1;
	for(int i=1;i<=m;i+=2)r[i]=__lg(m/i);
	for(int i=1;i<m;i+=2){
		for(int &j=r[i];~j;--j)if(vis[i<<j])break;
		if(r[i]==-1){for(int j=1;j<=n;j++)puts("No");return 0;}
		for(int j=3*i;j<=m;j+=2*i)r[j]=min(r[j],r[i]-1);
	} 
	for(int i=m-1;i>0;i-=2){
		for(int j=3*i;j<=m;j+=2*i)l[i]=max(l[i],l[j]+1);
		for(int &j=l[i];!vis[i<<j];++j);
	}
	for(int i=1;i<=n;i++){
		int x=a[i],y=0;
		while(x%2==0)x/=2,++y;
		puts(y>=l[x]&&y<=r[x]?"Yes":"No");
	}
    return 0;
}

E - Sliding Edge on Torus

题意:有个 \(N^2\) 个点的图,点用 \((i,j),0\leqslant i,j<N\) 表示。进行 \(Q\) 次连边,每次给定 \(a,b,c,d\),对于 \(\forall k\in[0,N)\) 连边 \(((a+k)\%N,(b+k)\%N)\)\(((c+k)\%N,(d+k)\%N)\),求每次连完的连通块数。

题解:\((i,j)\to (i-j,j)\),这样就是每次对两排点对应连边。考察一条排的链,则这条链会形成 \(N\) 条链,相邻之间有个偏移量,树亦然。那么一条非树边就相当于是在同一排中连边,连通块数就是 \(\gcd\)

可以用并查集维护之。具体的,对于每个连通块维护 \(f_i,g_i\) 表示父亲和答案。初始 \(f_i=i,g_i=N\)

我们还给每个点维护 \(h_i\) 表示它到根的偏移量。

对于一个询问 \((a,b,c,d)\) 转化为 \((u,v,p)=(a-b,c-d,d-b)\),然后分类讨论:

  • \(u,v\) 在同一连通块中,则 \(g\to \gcd(g,h_u-h_v-p)\)
  • 否则,令 \(U\)\(u\) 的根,\(V\)\(v\) 的根,\(g\to \gcd(g_U,g_V)\)\(U\)\(V\) 连边,\(U\) 子树加 \(h_v+p-h_u\)

时间复杂度 \(O(n\alpha(n))\)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int mod=1e9+7;
#define inf 1e9
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
int n,q,f[maxn],g[maxn],h[maxn];
long long ans;
inline int gcd(int x,int y){return !y?x:gcd(y,x%y);}
inline int find(int x){
	if(x==f[x])return x;int fa=find(f[x]);
	h[x]=(h[x]+h[f[x]])%n;return f[x]=fa;
}
inline void merge(int u,int v,int p){
	int x=find(u),y=find(v);
	if(x==y){
		ans-=g[x];
		g[x]=gcd(g[x],(h[u]-h[v]-p+n+n)%n);
		ans+=g[x];
	}else{
		ans-=g[x],ans-=g[y];
		f[x]=y;h[x]=(p-h[u]+h[v]+n)%n;
		g[y]=gcd(g[y],g[x]);
		ans+=g[y];
	}
}
int main(){
	n=read(),q=read();ans=1ll*n*n;
	for(int i=0;i<n;i++)f[i]=i,g[i]=n;
	for(int i=0,a,b,c,d;i<q;i++){
		a=read(),b=read(),c=read(),d=read();
		merge((a-b+n)%n,(c-d+n)%n,(d-b+n)%n);
		printf("%lld\n",ans);
	}return 0;
}

F - Well-defined Abbreviation

题意:给定 \(N\) 个由 A,B,C,D 组成的串 \(S_i(1\leqslant i\leqslant N)\)

对一个串 \(T\) 定义如下操作:

  • 选择一个 \(i\in[1,N]\),找到一个 \((l,r)\) 使得 \(T[l\cdots r]=S_i\)

  • \(T[l\cdots r]\)\(T\) 中删除,并把首尾拼接起来。

不断重复以上操作知道任意 \(S_i\) 都不是 \(T\) 的子串。

我们称 \(T\) 是好的,当且仅当操作后 \(T\) 是唯一的。判断是否存在不好的串。

posted @ 2022-08-31 13:25  syzf2222  阅读(68)  评论(0编辑  收藏  举报