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\) 是唯一的。判断是否存在不好的串。