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
题解
本文来自博客园,作者:Flying2018,转载请注明原文链接:https://www.cnblogs.com/Flying2018/p/15160044.html

浙公网安备 33010602011771号