A
发现翻转前后,字符串开头永远只能为第一个字母或最后一个,根据翻转次数分讨即可。
B
发现分块后的 mex \text{mex} mex 一定是序列本身的 mex \text{mex} mex,显然块与块之间是可以合并的,那么判断序列是否能分成两块即可。
C
比赛的时候傻了,其实是 d p dp dp 状态设计的不好。
发现题目等价于选出一些点,其花费为 b p k − b p 1 + ∑ i = 1 k a p k b_{p_k}-b_{p_1}+\sum_{i=1}^k a_{p_k} bpk−bp1+∑i=1kapk,求最多能选出多少个点。
显然应该将点按 b b b 排序,因为走回头路一定不优。
令 f i , j f_{i,j} fi,j 表示前 i i i 个点取了 j j j 个,并强制取第 i i i 个点的最小花费,有初始化 f i , 1 = a i − b i f_{i,1}=a_i-b_i fi,1=ai−bi,转移 f i , j = min k < i f k , j − 1 + a i f_{i,j}=\min_{k<i}{f_{k,j-1}+a_i} fi,j=mink<ifk,j−1+ai,前缀 min \min min 优化即可,最后判断 f i , j + b i ≤ l i m f_{i,j}+b_i \leq lim fi,j+bi≤lim 即可。
D
最简单的一集。
这个东西显然是不好求的,而且长得很容斥,拆成总方案数 − - − 和在集合 S S S 的方案数 − - − 差在集合 S S S 的方案数 + + + 和差都在集合 S S S 的方案数。
这些东西都是非常好维护的,时间复杂度 O ( n ) \text{O}(n) O(n)。
E
真降智吧。
考虑每一对 ( x , y ) (x,y) (x,y),公共前缀一定取,此时 x x x 的限制已经无效了,因为是根据 y y y 来取的。
我们考虑一个区间 [ l , r ] [l,r] [l,r],记有 k k k 个 y i y_i yi 第 j j j 位为 1 1 1,如果 k ≥ 2 k \geq 2 k≥2,那么直接令一个取 2 j 2^j 2j,一个取 2 j − 1 2^j-1 2j−1 即可;如果 k = 1 k=1 k=1,那么就取 2 j 2^j 2j;如果 k = 0 k=0 k=0 那么跳过即可。
至于公共前缀,用 s t st st 表处理一下即可。
F
有一个很明显的想法就是连接形如 ( i , i + 1 ) (i,i+1) (i,i+1) 的边一定最优,代价下界显然为 d e g u − 1 deg_u-1 degu−1。
考虑 edge case,若当前删除点 u u u 为 1 1 1 或 n n n,那么可以设每个连通块的最大值为 m x i mx_i mxi,有构造连接所有的 ( m x i , m x i + 1 ) (mx_i,mx_i+1) (mxi,mxi+1),那么代价就为 d e g u − 1 deg_u-1 degu−1。
那么类似的,我们也希望形如这样构造其他情况,讨论 m x i mx_i mxi 与 u u u 的关系:
若不存在 m x i mx_i mxi 满足 m x i + 1 = u mx_i+1=u mxi+1=u,那么直接像 u = 1 u=1 u=1 的情况构造即可。
否则我们考虑将整个序列 [ 1 , n ] [1,n] [1,n] 分为 [ 1 , u − 1 ] , [ u , u ] , [ u + 1 , n ] [1,u-1],[u,u],[u+1,n] [1,u−1],[u,u],[u+1,n] 的形式,若所有连通块里的数都只在其中的一段区间内出现,那么考虑将 [ 1 , u − 1 ] , [ u + 1 , n ] [1,u-1],[u+1,n] [1,u−1],[u+1,n] 分别连通,再连接 ( u − 1 , u + 1 ) (u-1,u+1) (u−1,u+1),代价为 d e g u deg_u degu。
若存在一个连通块内的数在 [ 1 , u − 1 ] , [ u + 1 , n ] [1,u-1],[u+1,n] [1,u−1],[u+1,n] 内都出现过,就可以省去上述的最后一步连接,使得代价为 d e g u − 1 deg_u-1 degu−1。
考虑重新规划策略,设 m n i mn_i mni 为一个连通块内最小的数,对于只在 [ 1 , u − 1 ] [1,u-1] [1,u−1] 内出现的块,连接 ( m n i − 1 , m n i ) (mn_i-1,mn_i) (mni−1,mni);对于所有 m x i > u mx_i>u mxi>u 的块,连接 ( m x i , m x i + 1 ) (mx_i,mx_i+1) (mxi,mxi+1)。
此时至少连接了 d e g u − 2 deg_u-2 degu−2 条边,特判一下就好。
m n , m x mn,mx mn,mx 可以换根 dp 计算,时间复杂度 O ( n ) \text{O}(n) O(n)。
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
const int N=2e5+5;
struct edge
{
int next,to;
}e[N<<1];
vector<pii> vc[N];
int n,cnt,in[N],mn[N],mx[N],anss[N],deg[N];
int read()
{
int res,f=1;
char ch;
while((ch=getchar())<'0'||ch>'9')
if(ch=='-')
f=-1;
res=ch^48;
while((ch=getchar())>='0'&&ch<='9')
res=(res<<1)+(res<<3)+(ch^48);
return res*f;
}
void add(int x,int y)
{
e[++cnt].next=in[x];
e[cnt].to=y;
in[x]=cnt;
}
void dfs1(int u,int fa)
{
int i,v;
mn[u]=mx[u]=u;
for(i=in[u];i;i=e[i].next)
{
v=e[i].to;
if(v==fa)
continue;
dfs1(v,u);
mn[u]=min(mn[u],mn[v]);
mx[u]=max(mx[u],mx[v]);
}
}
void dfs2(int u,int fa)
{
int i,v;
bool bz=0;
for(i=in[u];i;i=e[i].next)
{
v=e[i].to;
if(mx[v]==u-1)
{
bz=1;
break;
}
}
if(!bz||u==1||u==n)
{
anss[u]=deg[u]-1;
for(i=in[u];i;i=e[i].next)
{
v=e[i].to;
if(mx[v]<n&&mx[v]!=u-1)
vc[u].push_back(make_pair(mx[v],mx[v]+1));
}
}
else
{
for(i=in[u],bz=0;i;i=e[i].next)
{
v=e[i].to;
if(mn[v]<u&&mx[v]>u)
{
bz=1;
break;
}
}
if(!bz)
{
anss[u]=deg[u];
for(i=in[u];i;i=e[i].next)
{
v=e[i].to;
if(mx[v]+1==u)
vc[u].push_back(make_pair(mx[v],mx[v]+2));
else
if(mx[v]!=n)
vc[u].push_back(make_pair(mx[v],mx[v]+1));
}
}
else
{
int tmp=n;
anss[u]=deg[u]-1;
for(i=in[u];i;i=e[i].next)
{
v=e[i].to;
if(mx[v]<u&&mn[v]!=1)
vc[u].push_back(make_pair(mn[v]-1,mn[v]));
if(mx[v]>u)
{
if(mx[v]!=n)
vc[u].push_back(make_pair(mx[v],mx[v]+1));
tmp=min(tmp,mn[v]);
}
}
if(tmp<u&&tmp!=1)
vc[u].push_back(make_pair(tmp-1,tmp));
}
}
int mxm=0,mnm=1e9+7;
for(i=in[u];i;i=e[i].next)
{
v=e[i].to;
if(mx[v]!=n)
mxm=max(mxm,mx[v]);
if(mn[v]!=1)
mnm=min(mnm,mn[v]);
}
for(i=in[u];i;i=e[i].next)
{
v=e[i].to;
if(v==fa)
continue;
mx[u]=max(u,mx[v]==n?mxm:n);
mn[u]=min(u,mn[v]==1?mnm:1);
mx[v]=n;mn[v]=1;
dfs2(v,u);
}
}
void solve()
{
int i,j,x,y;
n=read();cnt=0;
for(i=1;i<=n;i++)
{
in[i]=deg[i]=anss[i]=0;
vc[i].clear();
}
for(i=1;i<=n-1;i++)
{
x=read();y=read();
deg[x]++;deg[y]++;
add(x,y);add(y,x);
}
dfs1(1,0);dfs2(1,0);
for(i=1;i<=n;i++)
{
printf("%d %d\n",anss[i],(int)vc[i].size());
for(j=0;j<(int)vc[i].size();j++)
printf("%d %d\n",vc[i][j].first,vc[i][j].second);
}
}
int main()
{
int T=read();
while(T--)
solve();
return 0;
}