gym-102452 香港区域赛部分题解
本人水平有限只会这几道题
B - Binary Tree
题意:给出一颗二叉树,Alice和Bob轮流删除子树,子树要求是完全二叉树。
在这里想了很久,什么模拟都来了,最后想了一下,好像退了几个样例找到了结论。
根据n的奇偶判答案
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200005;
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T, n;
cin >> T;
while (T--) {
cin >> n;
int u, v;
for (int i = 1; i < n; i++) {
cin >> u >> v;
}
if (n & 1) puts("Alice");
else puts("Bob");
}
return 0;
}
D - Defining Labels
这道题有点像进制转换,但有不完全是,注意细节,应该是减去前面的次方,在进行进制转换。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200005;
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
ll k, x;
cin >> k >> x;
if (x == 1) {
cout << 10 - k << endl;
continue;
}
ll s = k;
int count = 1;
while (x) {
if (x - s <= 0) break;
x -= s;
s *= k;
count++;
}
int t = 10 - k, st[110], cnt = 0;
x--;
while (x) {
st[++cnt] = x % k;
x /= k;
}
for (int i = 0; i < count - cnt; i++)
cout << t;
for (int i = cnt; i >= 1; i--) {
cout << st[i] + t;
}
cout << endl;
}
return 0;
}
G - Game Design
这道题就有点意思了,首先1和2 容易构造。
我拿到这道题马上就想到了,二进制拆分,因为有乘法关系,就想着偶数n/2 2,,奇数基础上加一,但不过总是WA6,不知道为啥。后来发现减一也不影响,就吧奇数合到了偶数那边。我估计正解应该是分解因子吧。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200005;
ll k, c[maxn], fa[maxn];
int ans[maxn], mx = 1;
ll dfs(ll k, int id) {
if (k == 1) {
return c[id] = 1;;
}
if (k == 2) {
c[id] = 1;
fa[++mx] = id;
c[mx] = 1;
return 1;
}
if (k & 1) {
k -= 1;
if (k == 2) {
fa[++mx] = id;
c[id] += dfs(2, mx);
} else {
fa[++mx] = id;
c[id] += dfs(k / 2, mx);
fa[++mx] = id;
c[id] += dfs(2, mx);
}
} else {
fa[++mx] = id;
c[id] += dfs(k - 1, mx);
}
return c[id];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> k;
if (k == 1) {
cout << 2 << endl;
cout << 1 << endl;
cout << "1 2" << endl;
return 0;
}
dfs(k, 1);
cout << mx << endl;
for (int i = 2; i <= mx; i++) {
if (i == mx) cout << fa[i] << endl;
else cout << fa[i] << " ";
}
for (int i = 1; i <= mx; i++) {
if (i == mx) cout << c[i] << endl;
else cout << c[i] << " ";
}
return 0;
}
J - Junior Mathematician
这道题就是要你求L到R的这个
x
=
f
(
x
)
(
m
o
d
m
)
x=f(x) (mod m)
x=f(x)(modm) 的数量
很明显数位DP
d
p
[
i
]
[
j
]
[
k
]
表
示
i
位
当
前
∑
t
f
(
x
,
t
)
(
m
o
d
m
)
=
j
,
(
f
(
x
)
−
x
)
(
m
o
d
m
)
=
k
dp[i][j][k]表示i位当前\sum_{t} f(x,t) (mod m)=j,(f(x)-x) (mod m)=k
dp[i][j][k]表示i位当前∑tf(x,t) (mod m)=j,(f(x)−x) (mod m)=k
d
p
[
i
]
[
j
]
[
k
]
转
移
d
p
[
i
+
1
]
[
j
+
p
o
s
[
i
]
]
[
k
+
j
∗
p
o
s
[
i
]
−
p
o
s
[
i
]
∗
1
0
k
−
i
+
1
]
dp[i][j][k]转移dp[i+1][j+pos[i]][k+j*pos[i]-pos[i]*10^{k-i+1}]
dp[i][j][k]转移dp[i+1][j+pos[i]][k+j∗pos[i]−pos[i]∗10k−i+1]
直接dp就可以了。注意比较卡常数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5010;
char s1[maxn], s2[maxn];
const ll mod = 1000000000 + 7;
int p[maxn], a[maxn], md;
ll dp[maxn][66][66];
ll dfs(int pos, int pre1, int pre2, bool limit) {
if (pos < 1) return !pre2;
if (!limit && dp[pos][pre1][pre2] != -1) return dp[pos][pre1][pre2];
ll ans = 0;
int up = (limit ? a[pos] : 9);
for (int i = 0; i <= up; i++) {
ans += dfs(pos - 1, (pre1 + i) % md, ((pre2 + i * pre1 - i * p[pos - 1]) % md + md) % md,
i == up && limit);
}
ans %= mod;
if (!limit) dp[pos][pre1][pre2] = ans;
return ans;
}
ll solve(char s[], int len) {
for (int i = 1; i <= len; i++)
for (int j = 0; j <= md; j++)
for (int k = 0; k <= md; k++)
dp[i][j][k] = -1;
// memset(dp, -1, sizeof(dp));
for (int i = 1; i <= len; i++) {
a[i] = s[len - i + 1] - '0';
}
return dfs(len, 0, 0, true);
}
int main() {
// ios::sync_with_stdio(false);
// cin.tie(0), cout.tie(0);
p[0] = 1;
int T;
scanf("%d", &T);
while (T--) {
scanf("%s %s %d", s1 + 1, s2 + 1, &md);
int n = strlen(s2 + 1);
int m = strlen(s1 + 1);
for (int i = 1; i <= n; i++)
p[i] = p[i - 1] * 10 % md;
s1[m]--;
for (int i = m; i >= 1; i--) {
if (s1[i] - '0' < 0) s1[i] += 10, s1[i - 1]--;
else break;
}
// cout << (solve(s2) - solve(s1) + mod) % mod << endl;
printf("%lld\n", (solve(s2, n) - solve(s1, m) + mod) % mod);
}
return 0;
}