https://codeforces.com/contest/1373

E. Sum of Digits

 

题意:给定n,k,问最小的x,满足 f(x)+f(x+1)++f(x+k)=nf(x) + f(x + 1) + \dots + f(x + k) = n,其中 f(x)f(x) 为 x 的各位数字和。1n150,0k91 \le n \le 150,0 \le k \le 9

贪心

由给定数据范围可知 x 最多进位一次。

枚举x的位数和最高位,对于每一种位数和最高位,只需要枚举后20个数。

对于任意一个数(位数足够多),一定可以变成次低位为8或9的数,且保持和不变,例如 479,可以变成 389。

且不能再缩小范围了,因为次低位小于8的可以变成8,但是次低位为8的和次低位为9的可能k个数和不同,因为9有进位。

而需要枚举最高位则是因为防止由于总和不够而增加位数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const int N = 1e6 + 10;
int T;
int n, k;
int cal(ll x) {
int ans = 0;
while (x) {
ans += x % 10;
x /= 10;
}
return ans;
}
ll sol() {
for (ll i = 10; i < 1e17; i *= 10) {
for (int j = 1; j < 10; j++) {
for (int p = 20; p >= 0; p--) {
ll t = i * j - p;
if (t < 0)continue;
int tmp = 0;
for (int q = 0; q <= k; q++) {
tmp += cal(t + q);
}
if (tmp == n)return t;
}
}
}
return -1;
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &k);
printf("%lld\n", sol());
}
return 0;
}

 

F. Network Coverage

 

题意:nn 个点环形排列,每点需要 a[i]a[i] 电力,每点有一个供电站,电量为 b[i]b[i],能为 ii(i+1)%n(i+1)\%n 供电,问能否满足所有点。

首先要发现流量是可以传递的,且沿着 i>i+1i->i+1 单向传递。

所以考虑向网络流一样先预流,再看能否往回流。

先把 b[0]b[0] 所有的流量都给 a[1]a[1],且后面所有节点每次优先使用 b[i1]b[i-1] 来填充 a[i]a[i],这样必然使得后面能获得的流量最多,如果这还不能满足,则直接GG。

但是这会使得 a[0]a[0] 没有流量,所以要把后面多余的流量再回流回来。

在预流的过程中维护 c[i]c[i],记录 a[i]a[i]b[i1]b[i-1] 获得了多少流量。

再从后向前遍历,如果还有 b[i]b[i],表示有多余,所以用 b[i]b[i] 代替 c[i]c[i] 中等量的一部分,流回 b[i1]b[i-1],即 b[i1]+=min(b[i],c[i])b[i-1]+=min(b[i],c[i])。最后判断 a[0]a[0] 能否满足。

注意 b[n1]b[n-1] 不能回流!其它点需要回流是因为其它点的 b[i]b[i] 没法直接对 a[0]a[0] 做出贡献,因此只能回流,而由于 b[n1]b[n-1] 可以直接加到 a[0]a[0] 里,所以不需要回流,并且由于回流的过程中可能受到容量限制,而流量变小,所以 b[n1]b[n-1] 更不能回流。

还有一种二分的思路。如果已知 b[0]b[0] 流多少到 a[1]a[1],则问题就解决了,所以要二分出 b[0]b[0] 流多少。如果全部流的话,必然要多出流量(否则直接GG),所以当某一刻流量不多了,这时的流量就是分界点,用这时的流量既能满足后面的,又能给 a[0]a[0] 有最多的流量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const int N = 1e6 + 10;
int T;
int n;
ll a[N], b[N], c[N];
bool ck1() {
for (int i = 1; i < n; i++) {
if (b[i - 1] + b[i] < a[i])return false;
c[i] = min(a[i], b[i - 1]);
b[i - 1] -= c[i];
b[i] -= a[i] - c[i];
}
return true;
}
bool ck2() {
for (int i = n - 2; i > 0; i--) {
b[i - 1] += min(b[i], c[i]);
}
return b[0] + b[n - 1] >= a[0];
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 0; i < n; i++)scanf("%lld", &a[i]);
for (int i = 0; i < n; i++)scanf("%lld", &b[i]);
fill(c, c + n, 0);
if (ck1() && ck2())puts("YES");
else puts("NO");
}
return 0;
}