Codeforces Round #660 (Div. 2)
A. Captain Flint and Crew Recruitment
题解
一般情况下是6,10,14,n-30都能满足,但是注意题中说要四个数互不相同,所以还得考虑当n-30=6,10,14的时候再自己构造一下。
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
int T,n;
int main()
{
T=read();
while(T--)
{
n=read();
if(n<=30)puts("NO");
else
{
if(n==36)puts("YES\n5 6 10 15");
else if(n==40)puts("YES\n6 10 15 9");
else if(n==44)puts("YES\n6 7 10 21");
else printf("YES\n%d %d %d %d\n",6,10,14,n-30);
}
}
return 0;
}
B. Captain Flint and a Long Voyage
题解
0~9里面肯定是8,9的二进制位最长,为了保证删后n位还是最大的,所以前3n位肯定全是9,后面的n位要全是8。注意要向上取整。
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
int T;
int main()
{
T=read();
while(T--)
{
int n=read();
int t=ceil((double)n/4.0);
for(int i=1;i<=n-t;i++)putchar('9');
for(int i=1;i<=t;i++)putchar('8');
puts("");
}
return 0;
}
C. Uncle Bogdan and Country Happiness
题解
这题我都不知道我怎么过的,做的时候全程懵逼
就先考虑每个子树,设当前在子树的有\(size\)个人,开心的有\(x\)个人,不开心的有\(size-x\),有\(2x=size+h[i]\),所以必须保证\(size+h\)必须是偶数,而且这个\(h\)必须在\([-size,size]\)区间里,否则不符合定义。然后开始考虑往儿子节点跑的过程,最坏情况下一路上可能大家全自闭了,所以这个东西没有下限,但是是有上限的,极限情况下在当前节点的人全自闭了,所以跑到儿子节点他们的\(\sum h_i\)不可能超过\(h_{now}+p_{now}\)。我就加了这么几个判断就A了,十分迷惑。
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int maxn=100010;
int n,first[maxn],ce,a,b;
LL m,val[maxn],size[maxn],h[maxn];
struct Edge
{
int u,v,next;
Edge() {}
Edge(int _1,int _2,int _3):u(_1),v(_2),next(_3) {}
}e[maxn<<1];
void addEdge(int a,int b)
{
e[++ce]=Edge(a,b,first[a]);first[a]=ce;
e[++ce]=Edge(b,a,first[b]);first[b]=ce;
}
bool ok;
void dfs(int now,int fa)
{
LL sum=0;
size[now]=val[now];
for(int i=first[now];i!=-1;i=e[i].next)
if(e[i].v!=fa)dfs(e[i].v,now),size[now]+=size[e[i].v];
if((size[now]+h[now])%2 || h[now]<-size[now] || h[now]>size[now]){ok=1;return;}
for(int i=first[now];i!=-1;i=e[i].next)
if(e[i].v!=fa)
sum+=h[e[i].v];
if(sum>h[now]+val[now]){
ok=1;return;
}
}
int main()
{
int T=read();
while(T--)
{
ce=-1;ok=0;
n=read();m=read();
for(int i=1;i<=n;i++)first[i]=-1,size[i]=0;
for(int i=1;i<=n;i++)val[i]=read();
for(int i=1;i<=n;i++)h[i]=read();
for(int i=1;i<n;i++)a=read(),b=read(),addEdge(a,b);
dfs(1,0);
if(!ok)puts("YES");
else puts("NO");
}
return 0;
}
D. Captain Flint and Treasure
题解
题目已经暗示的很明显了这个玩意是由若干棵有根树组成的,每一棵树的答案都是独立的,考虑依次处理树形DP,设\(dp_i\)表示i能取到的最大值,这个转移很简单,如果儿子的DP值是非负的,那么就可以累加上去。计算完答案后我们想如何还原答案,我一开始用的是双端队列在DP的时候插,感觉应该挺快的,结果pretest居然TLE了,于是就变成DP完了之后递归放数,对于一个\(now\),所有儿子\(dp[v]<0\)的都应放在\(now\)的后面,所有儿子\(dp[v]>=0\)的都应放在\(now\)的前面,做一个类似中序遍历的东西即可。
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int maxn=200010;
int n,a[maxn],b[maxn],ce=-1,first[maxn],prt[maxn],len,size[maxn];
LL dp[maxn],ans;
struct Edge
{
int u,v,next;
Edge() {}
Edge(int _1,int _2,int _3):u(_1),v(_2),next(_3) {}
}e[maxn<<1];
void addEdge(int a,int b)
{
if(a==-1)return;
e[++ce]=Edge(a,b,first[a]);first[a]=ce;
}
void DP(int now)
{
dp[now]=a[now];size[now]=1;
for(int i=first[now];i!=-1;i=e[i].next)
{
DP(e[i].v);
if(dp[e[i].v]>0)
dp[now]+=dp[e[i].v],size[now]+=size[e[i].v];
}
}
void put(int now)
{
for(int i=first[now];i!=-1;i=e[i].next)
if(dp[e[i].v]>0)put(e[i].v);
prt[++len]=now;
for(int i=first[now];i!=-1;i=e[i].next)
if(dp[e[i].v]<=0)put(e[i].v);
}
int main()
{
mem(first,-1);
n=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)b[i]=read(),addEdge(b[i],i);
for(int i=1;i<=n;i++)if(b[i]==-1)DP(i);
for(int i=1;i<=n;i++)if(b[i]==-1)put(i);
for(int i=1;i<=n;i++)ans+=dp[i];
printf("%lld\n%d",ans,prt[1]);
for(int i=2;i<=n;i++)printf(" %d",prt[i]);
return 0;
}