AtCoder Grand Contest 029

链接

C. Lexicographic constraints

首先二分答案,这样只需要想出一种最优的构造方法即可。

如果 \(a_{i+1}>a_i\),那么只要 \(s_{i+1}\)\(s_i\) 不断向后补齐 \(\texttt a\) 即可。否则先从后往前弹出字符直到长度小于等于 \(a_{i+1}\),然后模拟 \(k\) 进制 \(+1\) 操作即可。可以证明这样构造一定最优。

当然直接这么做显然会超时。考虑如何更快的处理。可以发现尽管字符串长度会很长,但是其中不为 \(a\) 的个数其实是 \(O(n)\) 的,因为加入一个字符串至多会增加一个不是 \(a\) 的字符。这样我们考虑用一个单调栈维护所有非 \(a\) 的位置和字符。而模拟加法的过程可以用加法器分析,均摊是 \(O(n)\) 的。

总复杂度 \(O(n\log n)\)

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 200010
using namespace std;
int ton[N],c[N],tp;
int a[N],n;
bool add(int x,int k)
{
    while(tp && ton[tp]>x) tp--;
    while(tp && ton[tp]==x && c[tp]==k) tp--,--x;
    if(!x) return false;
    if(!tp || ton[tp]!=x) ton[++tp]=x,c[tp]=2;
    else c[tp]++;
    return true;
}
bool check(int k)
{
    tp=0;bool fi=true;
    for(int i=1;i<=n;i++)
    if(i==1 || a[i]<=a[i-1])
    {
        // for(int j=1;j<=tp;j++) printf("%d,%d ",ton[j],c[j]);puts("");
        if(fi){fi=false;continue;}
        if(!add(a[i],k)) return false;
    }
    return true;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    bool inc=true;
    for(int i=2;i<=n;i++) if(a[i]<=a[i-1]) inc=false;
    if(inc){puts("1");return 0;}
    int l=2,r=n,res=1;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid)) r=mid-1,res=mid;
        else l=mid+1;
    }
    printf("%d",res);
    return 0;
}

E. Wandering TKHS

考虑换过来,对每一个 \(x\) 求出有多少个 \(y\) 对其有贡献。

如果一个 \(y\)\(x\) 有贡献,那么必然对 \(x\) 的子树中所有点都有贡献。所以考虑对于一个 \(y\),其能贡献的点深度最浅的是哪个。可以证明这个点一定在 \(y\) 到根路径上。

可以发现对于一个点 \(x\),令其到根路径上最大的点为 \(y\),那么 \(y\) 以下一定合法,\(y\) 以上一定不合法。所以唯一问题变成 \(y\) 是否合法。

这个很好处理,记录一下次大值,看一看次大值是否在 \(y\) 上方即可。复杂度 \(O(n)\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define N 200010
using namespace std;
vector<int>g[N];
int dep[N];
int mx[N],mx2[N],top[N],val[N];
void dfs(int u,int p)
{
    dep[u]=dep[p]+1;
    mx[u]=mx[p];mx2[u]=mx2[p];
    if(u>mx[u]) mx2[u]=mx[u],mx[u]=u,top[u]=u;
    else if(u>mx2[u]) mx2[u]=u;
    if(dep[mx2[u]]>dep[mx[u]]) ++val[top[u]];
    else ++val[mx[u]];
    for(int v:g[u]) if(v!=p)
    {
        top[v]=(mx[u]==u?v:top[u]);
        dfs(v,u);
    }
}
void push(int u,int p)
{
    val[u]+=val[p];
    for(int v:g[u]) if(v!=p) push(v,u);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),g[u].push_back(v),g[v].push_back(u);
    dfs(1,0);push(1,0);
    for(int i=2;i<=n;i++) printf("%d ",val[i]-1);
    return 0;
}

F. Construction of a tree

题解

posted @ 2023-09-20 18:58  Flying2018  阅读(10)  评论(0)    收藏  举报