AtCoder Grand Contest 052

链接

B. Tree Edges XOR

题解

考虑这类题目的常见套路是寻找一个不动量,即找到一个 f(S) 满足 S 操作后变成 Sf(S) 不变,然后尝试证明两个集合 S,T 可以互相到达当且仅当 f(S)=f(T)

在这里不妨对每个点构造点权 au,使得任意一条边 i 满足 auiavi=wi。但是注意到只有这样 au 不是唯一的。由于题面规定了 n 是奇数,所以我们令 ai=0,这样就存在唯一的 ai 了。

容易证明,任意一次操作后的结果只会交换两个点的点权。所以只需要看点权集合是否一致即可。复杂度 O(nlogn)

代码
#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 是质数,我们让所有数字 ×x1,序列的合法性不变。所以不妨设绝对众数为 1

考虑此时的策略。容易发现,只要某一刻 1 不再是绝对众数,这个序列就合法了。所以我们一定会尽可能多地填 1。注意不能填 1 时必然是 p1,那么此时填一个数字 x 在相当于给 1 续了 px 的长度。

可以发现,这个序列合法当且仅当对于所有 xi1(p1)+pxi 不小于 1 的个数。

那么我们直接枚举非 1 的数字之和,要求这个数字不能是 p 倍数,并且显然这个数 n。然后可以根据这个推出序列所有元素之和。这个就是拆分数的前缀和,可以直接预处理得到。

而所有是 p 倍数的方案数可以直接通过容斥 0 或者背包得到。复杂度 O(n2)

代码
#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 为 Lfi 表示以 i 结尾的 LIS 长度,考虑强行构造:

  • 如果 L 是偶数,那么将 L2 的序列划给集合 A,其余划给集合 B。首先如果集合中有 >L2 的 LIS,从 x 开始到 y 结束,那么 fy>fx+L2,显然不符合条件。同样集合中也必然存在长度为 L2 的 LIS。所以这样构造就是合法的。
  • 如果 L 是奇数,结论是存在 x 在长度至少为 k=L+12 的 LIS 中并且不在某一个上升序列中。求一个数是否一定在 LIS 中有点麻烦,事实上还可以证明的是如果存在,那么任意取一个 LIS 都会存在这样的点。
    考虑直接构造。如果存在这样的数,考虑取出包含 x 的任意长度为 k 的 LIS。设序列为 {pi},然后令集合 A 包含所有 fi 等于某个 fpj,特别的,如果 fi=fx,ix 则划给 B 集合。容易发现,A 集合中上升子序列必然为 k。而 B 中删去了所有除了 fx 外在 A 集合的所有层,所以上升子序列是 Lk+1,构造合法。

复杂度 O(nlogn)

代码
#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,构造 ai 使得 |aiai1|=1aisi(mod3)

容易发现,对于一个给定的 s,固定 a1 那么整个 a 都是固定的。每次操作等价于找到一个极小或者极大的位置,然后将其 ±2

结论:答案为 |aibi|2,当然 aibi 奇偶性必须相同。这显然是一个下界。对于上界,考虑给出这样一个构造:如果 a1=b1,直接跳过该位置。如果 a1<b1a2<a1,直接将 a12。否则不妨假设 a1<b1,a2>a1,那么找到第一个满足 ax+1<ax 的位置,注意到由于这一段斜率为 1,所以一定有 bx<ax,那么将这一段整体向下移 2,仍然符合答案。

复杂度 O(n)

posted @   Flying2018  阅读(17)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示