A
首先前三个符合题意的数字是
6
6
6
10
10
10
14
14
14
(
2
∗
3
,
2
∗
5
,
2
∗
7
)
(2*3 ,2*5,2*7)
(2∗3,2∗5,2∗7)
那么最小的数字一定需要大于30,因为n必须由正整数组成。
所以我们可以一开始放置
6
6
6
10
10
10
14
14
14三个数字,然后再使用n-30即可。
注意因为数字不能相同,所以需要判断一下,有相同的数字的话将14换成15。因为
10
−
6
=
4
,
14
−
10
=
4
10-6=4,14-10=4
10−6=4,14−10=4故某一个数字增大了1,那么不可能再有相等的数字存在。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t, n;
int main()
{
t = read();
while (t--)
{
n = read();
if (n <= 30) {
printf("NO\n");
}
else {
int a = 6, b = 10, c = 14, d = n - 30;
if (d == a || d == b || d == c)
{
if (n <= 31) {
printf("NO\n");
continue;
}
else {
c = 15;
d = n - 31;
}
}
printf("YES\n%d %d %d %d\n",a,b,c,d);
}
}
return 0;
}
B
首先每一个位置不是9就是8,因为这样二进制位数才是4的倍数,同时保证了总的二进制个数最多。然后是何时放置8的问题。因为我们需要最小的数字,所以当
n
m
o
d
4
!
=
0
n\mod4!=0
nmod4!=0会破坏掉某一个9,或者8的四位二进制数字的某几位。这个时候我们把9换成8即可。所以先假定全部都是9,然后求n会破坏掉几块,再把那几块对应的位置全部置换成8。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int t, n;
int main()
{
t = read();
while (t--)
{
n = read();
{
{
int pos = n / 4;
int mod = n % 4;
if (mod)pos++;
while (n > pos)
{
printf("9"); n--;
}
while (pos--)printf("8");
puts("");
}
}
}
return 0;
}
C
首先进行子树大小的计算,这里的子树大小规定为当前节点下面,一共有多少人,即每个点的流量。
我们知道了每一个点的流量,假设是
t
o
t
tot
tot。那么就可以写出方程式
h
a
p
p
y
−
b
a
d
=
h
i
happy-bad=h_i
happy−bad=hi
h
a
p
p
y
+
b
a
d
=
t
o
t
happy+bad=tot
happy+bad=tot,解出
h
a
p
p
y
happy
happy和
b
a
d
bad
bad首先判断他们的正确性,不是整数,小于零,都不行。然后进行树上贪心。可以看出,当从一个节点向下走到子节点的时候,如果全部都是
h
a
p
p
y
happy
happy那么一定可行,因为我们可以变化任意数量的人到
b
a
d
m
o
o
n
badmoon
badmoon。然后是如果流量里面带了
b
a
d
bad
bad,那么这个
b
a
d
bad
bad值一定不能大于子节点的
b
a
d
bad
bad值,这个时候我们只需要变化出流量-
b
a
d
bad
bad个人到
b
a
d
m
o
o
n
badmoon
badmoon即可。
假定我们执行到
u
u
u节点。设
u
u
u的子节点是
v
i
′
v'_{i}
vi′,当前节点有一个
b
a
d
bad
bad值
1.当
u
u
u节点能够容纳的人数>=
b
a
d
bad
bad的时候,我们将
b
a
d
bad
bad全部放在u节点。
2.当当
u
u
u节点能够容纳的人数<
b
a
d
bad
bad的时候,我们判断
∑
v
i
′
[
b
a
d
]
\sum{v'_i[bad]}
∑vi′[bad]是否能够满足
b
a
d
u
−
p
e
o
p
l
e
[
u
]
bad_u-people[u]
badu−people[u],如果能够,那么我们就将
b
a
d
u
−
p
e
o
p
l
e
[
u
]
bad_u-people[u]
badu−people[u]这么多人数,在从
u
u
u走到
v
v
v变成
b
a
d
bad
bad,因为已经计算
∑
v
i
′
[
b
a
d
]
\sum v'_i[bad]
∑vi′[bad]能够容纳,那么肯定符合题意,否则不行。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e5 + 10;
int T, n, m;
vector<int>vec[N];
ll p[N], h[N];
ll hm[N], bm[N];
void addedge(int u, int v)
{
vec[u].push_back(v);
vec[v].push_back(u);
}
ll sz[N];
void dfs1(int u, int fa) {
sz[u] = p[u];
for (auto k : vec[u])
{
if (k == fa)continue;
dfs1(k, u);
sz[u] += sz[k];
}
}
bool calc() {
upd(i, 1, n)
{
if ((h[i] + sz[i]) % 2ll) { return 0; }
hm[i] = (h[i] + sz[i]) / 2ll;
bm[i] = sz[i] - hm[i];
if (hm[i] < 0 || bm[i] < 0)return 0;
}
return 1;
}
bool flag = 0;
void dfs2(int u, int fa)
{
if (flag)return;
if (p[u] < bm[u]) {
ll tot = 0;
bm[u] -= p[u];
vector<int>tp;
for (auto k : vec[u])
{
if (k == fa)continue;
tot += bm[k];
tp.push_back(k);
}
if (tot < bm[u]) {
flag = 1; return;
}
/*sort(tp.begin(), tp.end(), [](int a, int b) {return bm[a] < bm[b]; });
dwd(i, tp.size() - 1, 0)
{
if (bm[tp[i]] >= bm[u])
{
bm[u] = 0; bm[tp[i]] -= bm[u]; break;
}
else {
bm[tp[i]] = 0; bm[u] -= bm[tp[i]];
}
}*/
}
for (auto k : vec[u])
{
if (k == fa)continue;
dfs2(k, u);
}
}
int main()
{
T = read();
while(T--)
{
n = read(), m = read();
flag = 0;
upd(i, 0, n)vec[i].clear();
upd(i, 1, n)p[i] = read();
upd(i, 1, n)h[i] = read();
int u, v;
upd(i, 1, n - 1) {
u = read(), v = read();
addedge(u, v);
}
dfs1(1, 0);
if (calc()) {
dfs2(1, 0);
if (flag)printf("NO\n");
else printf("YES\n");
}
else {
printf("NO\n");
}
}
return 0;
}
D
由题意,
b
[
n
]
b[n]
b[n]数组实际上我们通过观察可以发现,我们把
−
1
-1
−1也抽象成一个节点,就有
n
+
1
n+1
n+1个点和
n
n
n条边。又因为题意保证了没有环,且总能够走到
−
1
-1
−1,所以是一棵树。所以将该数组抽象成一棵树,进行树上dp。
令
d
p
[
u
]
dp[u]
dp[u]表示u节点所能够达到的最大值。又因为
u
u
u节点的值,当且仅能被所有的邻接子节点更新,假设是
v
i
′
v'_i
vi′,就有:
d
p
[
u
]
+
=
d
p
[
v
i
′
]
>
=
0
?
d
p
[
v
i
′
]
:
0
dp[u]+=dp[v'_i]>=0?dp[v'_i]:0
dp[u]+=dp[vi′]>=0?dp[vi′]:0。
又因为答案需要输出方案,所以我们开两个指针,一个从前到后
p
r
e
pre
pre,一个从后往前
s
u
f
suf
suf。当
d
p
[
u
]
被
v
i
′
dp[u]被v'_i
dp[u]被vi′更新的时候,更新到
p
r
e
pre
pre指针,否则更新到
s
u
f
suf
suf指针。
合理性显然,因为我们自底而上,每次更新当前节点的时候,时间一定会在子节点的后面或者之前。将合并的信息放前面,不合并的点放后面,就不会有任何的影响。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 2e5 + 10;
vector<int>vec[N];
void addedge(int u, int v)
{
vec[u].push_back(v);
vec[v].push_back(u);
}
int n;
ll a[N];
ll b[N];
ll dp[N];
int ans[N]; int cnt = 0; int last = 0;
ll sum = 0;
int sz[N];
void dfs2(int u, int fa)
{
sz[u] = 1;
for (auto k : vec[u])
{
if (k == fa)continue;
dfs2(k, u);
sz[u] += sz[k];
}
}
void dfs(int u, int fa)
{
dp[u] = a[u];
for (auto k : vec[u])
{
if (k == fa)continue;
dfs(k, u);
if (dp[k]>=0) {
dp[u] += dp[k];
ans[++cnt] = k;
}
else {
ans[last--] = k;
}
}
if(u!=0)
sum += dp[u];
}
int main()
{
n = read();
upd(i, 1, n)a[i] = read();
last = n;
upd(i, 1, n)
{
b[i] = read();
addedge(i, b[i] == -1 ? 0 : b[i]);
}
dfs2(0, 0);
dfs(0, 0);
cout << sum << endl;
upd(i, 1, n)
{
printf("%d ", ans[i]);
}
return 0;
}