AtCoder Grand Contest 052
链接
B. Tree Edges XOR
题解
考虑这类题目的常见套路是寻找一个不动量,即找到一个 \(f(S)\) 满足 \(S\) 操作后变成 \(S'\) 时 \(f(S')\) 不变,然后尝试证明两个集合 \(S,T\) 可以互相到达当且仅当 \(f(S)=f(T)\)。
在这里不妨对每个点构造点权 \(a_u\),使得任意一条边 \(i\) 满足 \(a_{u_i}\oplus a_{v_i}=w_i\)。但是注意到只有这样 \(a_u\) 不是唯一的。由于题面规定了 \(n\) 是奇数,所以我们令 \(\bigoplus a_i=0\),这样就存在唯一的 \(a_i\) 了。
容易证明,任意一次操作后的结果只会交换两个点的点权。所以只需要看点权集合是否一致即可。复杂度 \(O(n\log n)\)。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int nxt[N<<1],to[N<<1],w1[N<<1],w2[N<<1],a[N],b[N],head[N],cnt;
void add(int u,int v,int W1,int W2){nxt[++cnt]=head[u];to[cnt]=v;w1[cnt]=W1,w2[cnt]=W2;head[u]=cnt;}
void dfs(int u,int p){for(int i=head[u];i;i=nxt[i]) if(to[i]!=p){int v=to[i];a[v]=a[u]^w1[i],b[v]=b[u]^w2[i],dfs(v,u);}}
int main()
{
int n,x1=0,x2=0;scanf("%d",&n);
for(int i=1;i<n;i++)
{
int u,v,w1,w2;scanf("%d%d%d%d",&u,&v,&w1,&w2);
add(u,v,w1,w2),add(v,u,w1,w2);
}
dfs(1,0);
for(int i=1;i<=n;i++) x1^=a[i],x2^=b[i];
for(int i=1;i<=n;i++) a[i]^=x1,b[i]^=x2;
sort(a+1,a+n+1),sort(b+1,b+n+1);
for(int i=1;i<=n;i++) if(a[i]!=b[i]){puts("NO");return 0;}
puts("YES");
return 0;
}
C. Nondivisible Prefix Sums
题解
明哥题。
考虑先找到判断一个序列是否是“好的”的充要条件。首先显然整个序列的和模 \(p\) 不能是 \(0\)。可以注意到,假如接下来我们想要填 \(p\),但是 \(p\) 不合法,那么我们先填一个其他数字,那么 \(p\) 一定可以在下一次被填上。所以可以证明,如果一个长度为 \(m\) 的序列中不存在绝对众数,那么它一定合法。
假如一个序列中存在绝对众数,不妨设其为 \(x\)。由于 \(p\) 是质数,我们让所有数字 \(\times x^{-1}\),序列的合法性不变。所以不妨设绝对众数为 \(1\)。
考虑此时的策略。容易发现,只要某一刻 \(1\) 不再是绝对众数,这个序列就合法了。所以我们一定会尽可能多地填 \(1\)。注意不能填 \(1\) 时必然是 \(p-1\),那么此时填一个数字 \(x\) 在相当于给 \(1\) 续了 \(p-x\) 的长度。
可以发现,这个序列合法当且仅当对于所有 \(x_i\neq 1\),\((p-1)+\sum p-x_i\) 不小于 \(1\) 的个数。
那么我们直接枚举非 \(1\) 的数字之和,要求这个数字不能是 \(p\) 倍数,并且显然这个数 \(\leq n\)。然后可以根据这个推出序列所有元素之和。这个就是拆分数的前缀和,可以直接预处理得到。
而所有是 \(p\) 倍数的方案数可以直接通过容斥 \(0\) 或者背包得到。复杂度 \(O(n^2)\)。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=5010,mod=998244353;
int _p[N],f[N],g[N];
int ksm(int a,int b=mod-2)
{
int r=1;
for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) r=1ll*r*a%mod;
return r;
}
void add(int &x,int y){x=(x+y>=mod?x+y-mod:x+y);}
void dec(int &x,int y){x=(x-y<0?x-y+mod:x-y);}
int main()
{
int n,p; scanf("%d%d",&n,&p);
f[0]=1;
for(int i=1;i<=n;i++)
{
g[0]=f[0];for(int j=1;j<=n;j++) g[j]=(g[j-1]+f[j])%mod;
for(int j=2;j<=n;j++) add(f[j],(g[j-2]-(j>=p?g[j-p]:0)+mod)%mod);
}
int res=1ll*(ksm(p-1,n)+(n&1?mod-(p-1):(p-1)))*ksm(p)%mod;
res=(ksm(p-1,n)-res+mod)%mod;
for(int i=0;i<=n-p;i++) if((n-i)%p) dec(res,1ll*(p-1)*f[i]%mod);
printf("%d\n",res);
return 0;
}
D. Equal LIS
题解
结论题。设序列 LIS 为 \(L\),\(f_i\) 表示以 \(i\) 结尾的 LIS 长度,考虑强行构造:
- 如果 \(L\) 是偶数,那么将 \(\leq \frac L2\) 的序列划给集合 \(A\),其余划给集合 \(B\)。首先如果集合中有 \(>\frac L2\) 的 LIS,从 \(x\) 开始到 \(y\) 结束,那么 \(f_y>f_x+\frac L2\),显然不符合条件。同样集合中也必然存在长度为 \(\frac L2\) 的 LIS。所以这样构造就是合法的。
- 如果 \(L\) 是奇数,结论是存在 \(x\) 在长度至少为 \(k=\frac{L+1}{2}\) 的 LIS 中并且不在某一个上升序列中。求一个数是否一定在 LIS 中有点麻烦,事实上还可以证明的是如果存在,那么任意取一个 LIS 都会存在这样的点。
考虑直接构造。如果存在这样的数,考虑取出包含 \(x\) 的任意长度为 \(k\) 的 LIS。设序列为 \(\{p_i\}\),然后令集合 \(A\) 包含所有 \(f_i\) 等于某个 \(f_{p_j}\),特别的,如果 \(f_i=f_x,i\neq x\) 则划给 \(B\) 集合。容易发现,\(A\) 集合中上升子序列必然为 \(k\)。而 \(B\) 中删去了所有除了 \(f_x\) 外在 \(A\) 集合的所有层,所以上升子序列是 \(L-k+1\),构造合法。
复杂度 \(O(n\log n)\)。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=200010;int n,f[N],g[N],a[N],t[N];
void clear(){for(int i=1;i<=n;i++) t[i]=0;}
void add(int x,int v){for(;x<=n;x+=x&-x) t[x]=max(t[x],v);}
int qry(int x){int v=0;for(;x;x-=x&-x) v=max(v,t[x]);return v;}
int main()
{
int T;scanf("%d",&T);
while(T --> 0)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
clear();for(int i=1;i<=n;i++) add(a[i],f[i]=qry(a[i])+1);
int res=qry(n);
if(res%2==0){puts("YES");continue;}
clear();for(int i=n;i;i--) add(n-a[i]+1,g[i]=qry(n-a[i]+1)+1);
bool can=false;
for(int i=n,j=res;i;j-=f[i]==j,i--) if(f[i]!=j && f[i]+g[i]>res/2+1){can=true;break;}
puts(can?"YES":"NO");
for(int i=1;i<=n;i++) f[i]=g[i]=0;
}
return 0;
}
E. 3 Letters
题解
考虑构造这样一个序列:令 \(A,B,C\) 分别为 \(0,1,2\),构造 \(a_i\) 使得 \(|a_i-a_{i-1}|=1\) 且 \(a_i\equiv s_i\pmod 3\)。
容易发现,对于一个给定的 \(s\),固定 \(a_1\) 那么整个 \(a\) 都是固定的。每次操作等价于找到一个极小或者极大的位置,然后将其 \(\pm 2\)。
结论:答案为 \(\sum\frac{|a_i-b_i|}2\),当然 \(a_i\) 和 \(b_i\) 奇偶性必须相同。这显然是一个下界。对于上界,考虑给出这样一个构造:如果 \(a_1=b_1\),直接跳过该位置。如果 \(a_1<b_1\) 且 \(a_2<a_1\),直接将 \(a_1\) 减 \(2\)。否则不妨假设 \(a_1<b_1,a_2>a_1\),那么找到第一个满足 \(a_{x+1}<a_x\) 的位置,注意到由于这一段斜率为 \(1\),所以一定有 \(b_x<a_x\),那么将这一段整体向下移 \(2\),仍然符合答案。
复杂度 \(O(n)\)。

浙公网安备 33010602011771号