https://atcoder.jp/contests/abc161/tasks

C - Replacing Integer

 

题意:给定x,k,每次操作把x变为 xk|x-k|,问x最小值。

考虑x<k的情况,则此时只会在x,k-x这两个数里变化,找到小的那个即可,而如果x大于k,则一定可以变为x<k。

1
2
3
4
5
6
7
8
9
10
11
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
ll n, k;
int main() {
cin >> n >> k;
cout << min(n%k, k - n % k) << endl;
return 0;
}

 

D - Lunlun Number

 

题意:要求的数相邻十进制位的差值必须小于等于1,问第x个这样的数是几。

x最大只有1e5,而这样的数的个数是随着位数以幂次增长的,所以最终位数一定不大,直接dfs预处理出所有的,再直接输出。

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
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
vector<ll>vc;
void dfs(int dep, ll pre) {
if (dep == 0) {
vc.push_back(pre);
return;
}
int p = pre % 10;
for (int i = max(0, p - 1); i <= min(9, p + 1); i++) {
dfs(dep - 1, pre * 10 + i);
}
}
int main() {
int num = 1;
while (1) {
for (int i = 1; i <= 9 && (int)vc.size() < 100000; i++) {
dfs(num - 1, i);
}
if ((int)vc.size() >= 100000)break;
num++;
}
sort(vc.begin(), vc.end());
int n;
cin >> n;
printf("%lld\n", vc[n - 1]);
return 0;
}

 

E - Yutori

 

题意:共有n天,需要工作k天,且当天工作后,后面c天必须休息,且给定字符串为‘x’的那天不能工作,问哪几天必须工作。

贪心

首先要发现,贪心的能工作就工作,一定可以工作最多天,因为今天工作了,冷却地更早,比明天工作有更多选择余地。

然后就是要判断当天如果不工作,完不成任务,那么当天就必须工作。

先从左到右贪心处理出前i天最多工作几天,再从右到左类似处理出以最后一天为第一天,后i天最多工作几天。

然后第i天不工作,则最多工作天数=前i-1天最多的工作天数+第i+1天起第一个能工作的日子后最多工作的天数。

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
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
int n, k, c;
char s[N];
int f[N], g[N], fr[N], bk[N];
int main() {
scanf("%d%d%d", &n, &k, &c);
scanf("%s", s + 1);
for (int i = 1; i <= n; i++) {
bk[i] = bk[i - 1];
f[i] = f[i - 1];
if (i >= bk[i] && s[i] == 'o') {
f[i]++;
bk[i] = i + c + 1;
}
}
fr[n + 1] = n + 1;
for (int i = n; i >= 1; i--) {
fr[i] = fr[i + 1];
g[i] = g[i + 1];
if (i <= fr[i] && s[i] == 'o') {
g[i]++;
fr[i] = i - c - 1;
}
}
for (int i = 1; i <= n; i++) {
if (s[i] == 'x')continue;
if (f[i - 1] + g[max(i + 1, bk[i - 1])] < k)printf("%d\n", i);
}
return 0;
}

 

F - Division or Substraction

 

题意:操作:如果k整除n,则n/=k,否则n-=k。重复操作直到n小于k。问有几个k,能使最终的n值为1.

n=kp(ak+1)n=k^p\cdot(ak+1),则先枚举n的因子(p不为0),再枚举n-1的因子(p为0),注意去重和结果再算上n-1和n。

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
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
ll n;
int main() {
cin >> n;
ll ans = 0;
if (n == 2) { puts("1"); return 0; }
for (ll k = 2; k*k <= n; k++) {
if (n%k)continue;
ll tmp = n;
while (tmp%k == 0)tmp /= k;
if (tmp%k == 1)ans++;
tmp = n;
ll b = n / k;
while (tmp%b == 0)tmp /= b;
if (tmp%b == 1)ans++;
if (b == k)ans--;
}
for (ll k = 2; k*k <= (n - 1); k++) {
if ((n - 1) % k != 0 || (n%k) == 0)continue;
ans++;
ll b = (n - 1) / k;
if (b == k || (n - 1) % b != 0 || (n%b) == 0)continue;
ans++;
}
printf("%lld\n", ans + 2);
return 0;
}