Codeforces Round 1004 (Div. 2)-交互题、数学题
比赛主页:Codeforces Round 1004 (Div. 2)
目录:
A. Adjacent Digit Sums
B. Two Large Bags
C. Devyatkino
D. Object Identification
A. Adjacent Digit Sums
A. Adjacent Digit Sums
题意:
给定两个整数 x, y,问是否存在一个整数 n,使得 S(n) = x, S(n+1) = y
其中 S(n) 表示整数 n 的数位和
思路:
- 如果发生进位,那么数位和的变化值将会是:进位次数 * 9-1,只需要判断( x - y+1 )% 9 是否为 0 即可
- 前提是 x-y+1 > 0
- 或则没有发生进位,那么 y=x+1
// https://codeforces.com/contest/2067/problem/A
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1e9 + 7;
int T, n, m, k;
void solve()
{
cin >> n >> m;
if ((n + 1 == m) || (n - m + 1 > 0 && (n - m + 1) % 9 == 0))
cout << "YES\n";
else
cout << "NO\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
B. Two Large Bags
B. Two Large Bags
题意:
有两个背包 a, b,一开始背包 a 中有 n 个数,你可以进行以下操作无限次:
- 将 a 中的一个数字 number 放到 b 中
- 如果 a、b 中都存在数字 number,那么背包 a 中的 number+1(数值+1,不是数量+1),背包 b 中的 number 不变
问是否可以通过任意次操作使得 a = b,即每种数字的数量都相同
思路:
- 我们需要让每种数的出现次数为偶数,而且只能 +1,所以可以从后往前遍历
- 如果 cnt[i] 是奇数,那么就需要将 i-1 的数 +1 得到 i
- 那么需要多少个呢?
- cnt[i] 是奇数,那么还需要 1 个 i-1,所以需要 1 个 i-1 变到 i,而且每种数必须出现偶数次,那么至少需要 3 个 i-1,
- 那就再看 i-1 有多少个,需不需要往更小的数借数,以此类推,每层都需要 ans + 2
- 如果到了哪一层 cnt[x](x<i) 足够变这么多个 i 了,那就继续往下遍历,找是奇数的位置
- 如果最后遍历到 1 位置了,ans 还没有被消掉,那么就是 NO 了
// https://codeforces.com/contest/2067/problem/B
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1e9 + 7;
int T, n, m, k;
int cnt[1003];
void solve()
{
cin >> n;
for (int i = 0; i <= n; i++)
cnt[i] = 0;
for (int i = 0, x; i < n; i++)
cin >> x, cnt[x]++;
int ans = 1;
for (int i = n; i >= 1; i--)
{
if (cnt[i] & 1)
{
while (i >= 1)
{
if (cnt[i - 1] >= ans + 2)
{
cnt[i - 1] -= ans + 2;
ans = 1;
break;
}
else
ans = ans + 2 - cnt[i - 1];
i--;
}
if (i < 1)
{
cout << "NO\n";
return;
}
}
}
cout << "YES\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
C. Devyatkino
C. Devyatkino
题意:
给定一个整数 n,可进行以下操作:
- 给 n 加上 10^x - 1(x >= 1)即(9、99、999、...、99999999...)
求最少操作次数使得 n 的数位中存在 7
思路:
- 答案不够超过 9,因为 9 * 9 = 1,9 * 8 = 2,9 * 7 = 3,末位从 1~9 都覆盖了,最多加 9 次
- 加 n 位的 99...9 相当于在 n+1 位加 1,在末位上 -1
- 暴力遍历 +9、+99、+999....,0 次、1 次、2次....
- 时间复杂度 O(1e3)
// https://codeforces.com/contest/2067/problem/C
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1e9 + 7;
int T, n, m, k;
void solve()
{
cin >> n;
int ans = 10;
for (int i = 0; i <= 10; i++)
{
for (int j = 0; j <= 9; j++)
{
int temp = n + j * (pow(10, i) - 1);
while (temp)
{
if (temp % 10 == 7)
{
ans = min(ans, j);
break;
}
temp /= 10;
}
}
}
cout << ans << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
D. Object Identification
D. Object Identification
题意:
交互题
给定两个长度为 n 的数组 X、Y,你知道数组 X 的每个值,但是你不知道数组 Y 的值;知道对于每个下标 i 满足:X[i] != Y[i];知道对于所有组合(X[i], Y[i])都不同。
裁判预先设定了答案 A 或者答案 B,在程序运行中不会改变,答案需要你通过询问的方式来猜
- 答案 A:一个由 n 个节点,n 条边组成的有向图,第 i 条边为 Xi -> Yi
- 答案 B:一个平面坐标,由 n 个点组成,第 i 个点为 (Xi, Yi)
你最多可以做两次询问,每次询问格式为 "? i j"
裁判会回答一个整数 number
- 如果答案是 A,那么 number 代表节点 i 到节点 j 的最短路的边数
- 如果答案是 B,那么 number 代表第 i 个点到第 j 个点的曼哈顿距离,即 |Xi - Xj| + |Yi - Yj|
如果你已经知道答案,那么请输出 "! A" 表示你猜的答案为 A,或者 "! B" 表示你猜的答案为 B
思路:
- 如果 x 不是排列,那么就看没出现的数,假设 a 没有出现过,那么只需要判断 (a,*),如果读入 0,那么就是 A,否则为 B
- 因为如果是 A,那么如果不存在 a -> * 的路径,那么肯定读入 0,如果读入非 0,那么就是 B 了
- 如果 x 是排列,查询等于 1,n 的位置,如果 读入的数相等并且大于等于 n-1,那说明是 B,否则为 A
- 因为 如果是 A,那么两个节点之间的距离不会 > n-1,而且是有向图,也不肯能相等
// https://codeforces.com/contest/2067/problem/D
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1e9 + 7;
int T, n, m, k;
void solve()
{
cin >> n;
vector<int> v(n + 1, 0), g(n + 1);
for (int i = 1; i <= n; i++)
cin >> g[i], v[g[i]] = 1;
int a, b;
for (int i = 1; i <= n; i++)
{
if (v[i] == 0)
{
cout << "? " << i << " " << 1 + (i == 1) << endl;
cout.flush();
cin >> a;
cout << (a == 0 ? "! A" : "! B") << endl;
cout.flush();
return;
}
}
int idx1, idxn;
for (int i = 1; i <= n; i++)
{
if (g[i] == 1)
idx1 = i;
if (g[i] == n)
idxn = i;
}
cout << "? " << idx1 << " " << idxn << endl;
cout.flush();
cin >> a;
cout << "? " << idxn << " " << idx1 << endl;
cout.flush();
cin >> b;
cout << ((a == b && a >= n - 1) ? "! B" : "! A") << endl;
cout.flush();
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}