Educational Codeforces Round 122 (Rated for Div. 2) ABCD
A. Div. 7
给一个数,问最少修改多少位可以让这个数被7整除。
注意到7小于10,因此每10个数必然有一个7,所以最多只需要修改一次个位即可。
#include <iostream>
#include <cmath>
#define ll long long
using namespace std;
int main() {
int t;
cin >> t;
while(t--) {
int n;
cin >> n;
if(n % 7 == 0) cout << n << endl;
else {
int a = n / 10 * 10;
for(int i = 0; i < 9; i++) {
if((a + i) % 7 == 0) {
cout << a + i << endl;
break;
}
}
}
}
return 0;
}
B. Minority
给一个01字符串,可以选择一个子串,如果其中0的个数严格大于1的个数则将1删掉,如果1的个数严格大于0的个数则将0删掉,问最多能删掉多少数。
首先如果整个串中0和1个数不一样,那么直接选整个串即可;如果一样的话,则选除这个串第一个字符外剩下所有字符构成的子串,这样显然答案最大。
#include <iostream>
#include <cmath>
#define ll long long
using namespace std;
int main() {
int t;
cin >> t;
while(t--) {
string s;
cin >> s;
int zero = 0, one = 0;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '0') zero++;
else one++;
}
if(zero == one) cout << zero - 1 << endl;
else cout << min(zero, one) << endl;
}
return 0;
}
C. Kill the Monster
最关键的是要注意到k的范围总共才2e5,自然想到枚举k然后判断能否击败。几百的条件是character攻击的次数小于等于怪物攻击的次数。
#include <iostream>
#include <cmath>
#define ll long long
using namespace std;
ll hc, dc, hm, dm, k, w, a;
bool check() {
ll num1 = ceil(1.0 * hm / dc);
ll num2 = ceil(1.0 * hc / dm);
return num1 <= num2;
}
int main() {
int t;
cin >> t;
while(t--) {
cin >> hc >> dc;
cin >> hm >> dm;
cin >> k >> w >> a;
//注意k的和不超过2e5
bool ok = 0;
for(ll i = 0; i <= k; i++) {//有i个加hc
hc += i * a;
dc += (k - i) * w;
if(check()) {
ok = 1;
break;
}
hc -= i * a;
dc -= (k - i) * w;
}
if(ok) puts("YES");
else puts("NO");
}
}
D. Make Them Equal
首先注意到,因为每个ai起始都为1,因此ai到达bi的次数是固定的。可以预处理出1到1000范围内从1变换到每个数的次数,然后实际上这个问题就变成了一个最简单的01背包模型。预处理的话我一开始想到的是倍增/枚举因子贪心,然而实际上这样得到的不一定是最优解。一个正确的做法是求一遍最短路,起点为1,a到b路径长度是从a变换到b的次数。还有一点需要注意,输入说明中显示k范围1e6,如果dp数组第二维直接开1e6必然TLE/MLE。而b的范围是1000,按照纯倍增做法,一个数至多变换2log1000次,如果再枚举因子贪心的话变换次数还会降低,实测每个数变换次数上界为13,因此若干k大于n * 13则直接取k = n * 13即可。
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
int n, k, dp[13005], a[1005], b[1005], c[1005], num[1005], f[1005], v[1005];
void dijkstra() {
memset(v, 0, sizeof(v));
memset(f, 0x3f, sizeof(f));
priority_queue<pair<int, int> > q;
f[1] = 0;
q.push(make_pair(0, 1));
while(q.size()) {
int now = q.top().second;
q.pop();
if(v[now]) continue;
v[now] = 1;
for(int i = 1; i <= now; i++) {
int nxt = now + now / i;
if(nxt <= 1000 && f[nxt] > f[now] + 1) {
f[nxt] = f[now] + 1;
q.push(make_pair(-f[nxt], nxt));
}
}
}
}
int main() {
int t;
cin >> t;
dijkstra();
while(t--) {
cin >> n >> k;
for(int i = 0; i <= 13000; i++) dp[i] = 0;
for(int i = 1; i <= n; i++) {
cin >> b[i];
a[i] = 1;
num[i] = 0;
}
for(int i = 1; i <= n; i++) {
cin >> c[i];
}
for(int i = 1; i <= n; i++) {
num[i] = f[b[i]];
}
int ans = 0;
for(int i = 1; i <= n; i++) {
for(int j = min(k, 13 * n); j - num[i] >= 0; j--) {
dp[j] = max(dp[j], dp[j - num[i]] + c[i]);
ans = max(ans, dp[j]);
}
}
cout << ans << endl;
}
return 0;
}
// 7 12
// 11 57 71 26 31 99 58
// 62 66 82 31 94 18 74