(6/6) Codeforces Round #455 (Div. 2)
A. Generate Login
题意:
给你两个字符串a,b要求取a的任意前缀和b的任意前缀结合,要求最后得到的字符串字典序最小。
思路:
首先a的第一个字符一定要取,接下来从a的第二个字符和b的首字符开始,比较a的每一位和b的每一位,如果a的字符小放a再循环比较;否则放b,退出循环。如果a全部放进去了,那么接下来放b的第一个字符。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
void work() {
string a, b;
cin >> a >> b;
string res;
res += a[0];
int sza = a.size(), szb = b.size();
int f = 0;
// cout << res << endl;
for (int i = 1, j = 0; i < sza;) {
if (a[i] < b[j]) {
res += a[i];
i++;
} else {
res += b[j];
f = 1;
break;
}
}
if (f) cout << res << endl;
else {
res += b[0];
cout << res << endl;
}
}
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int cas;
cas = 1;
while (cas--) work();
}
B. Segments
题意:
给你一个数n,在x轴上从0到n一共n+1个点。
从n+1个点任取两个就可以组成线段。问需要多少个x轴才能把所有线段覆盖。
如:n为4需要6个x轴。
思路:
n+1个点把x轴分为n个边,枚举任意两个点,对对应的边加上权值1,答案为权值最大的边。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
int v[1000];
void work() {
int n;
cin >> n;
for (int i = 0; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
for (int k = i; k < j; k++) v[k + 1]++;
}
}
int ans = 0;
for (int i = 1; i <= n; i++) ans = max(ans, v[i]);
cout << ans << endl;
}
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int cas = 1;
while (cas--) work();
}
C. Python Indentation
题意:
给你一串字符包含s和f,f代表for循环,s代表语句。
在python中用缩进代表代码块,问此字符串一共可以组成多少种代码。
思路:
f [ i , j ] f[i, j] f[i,j]代表第 i i i个语句缩进为 j j j。那么第 n n n位最多缩进 n − 1 n-1 n−1,所以答案为 ∑ ( f [ n , 0 ] , f [ n , 1 ] . . . f [ i , n − 1 ] ) \sum(f[n,0], f[n, 1]...f[i,n-1]) ∑(f[n,0],f[n,1]...f[i,n−1])。
那么如果当前位为 f f f,那么下一位一定缩进。 f [ i + 1 , j + 1 ] = f [ i , j ] f[i+1, j+1]=f[i,j] f[i+1,j+1]=f[i,j]。如果当前位为 s s s,那么下一位最多等于上一位的缩进,最小不缩进。所以对于下一位的缩进 k k k, f [ i + 1 , k ] = ∑ ( f [ i + 1 , k ] , f [ i + 1 , k + 1 ] . . . f [ i , n − 1 ] ) f[i+1, k]=\sum(f[i+1,k], f[i+1,k+1]...f[i,n-1]) f[i+1,k]=∑(f[i+1,k],f[i+1,k+1]...f[i,n−1])。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
constexpr int mod = 1e9 + 7;
int f[5010][5010];
int a[5010];
void work() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
string x;
cin >> x;
if (x[0] == 's') a[i] = 1;
else a[i] = 0;
}
f[1][0] = 1;
for (int i = 1; i <= n; i++) {
if (a[i] == 0) {
for (int j = 0; j <= n - 1; j++)
(f[i + 1][j + 1] = f[i][j]) %= mod;
} else {
int sum = 0;
for (int j = n - 1; j >= 0; j--) {
(sum += f[i][j]) %= mod;
f[i + 1][j] = sum;
}
}
}
int ans = 0;
for (int i = 0; i <= n - 1; i++) (ans += f[n][i]) %= mod;
cout << (ans % mod + mod) % mod << endl;
}
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int cas;
cas = 1;
while (cas--) work();
}
D. Colorful Points
题意:
给你一个字符串仅包含 a a a到 z z z中的任意个字符,对于每次操作,对于每个字符,如果两侧存在至少一个字符与当前字符不同,则此字符可以删除。问最少进行多少次操作才不能操作。
思路:
暴力模拟,把相邻的且相同的字符归为一类放在新开辟的数组中,当数组中的元素小于等于1时,操作停止。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
using pii = pair<int, int>;
void work() {
string s;
cin >> s;
vector<pii> v;
for (int i = 0; i < (int)s.size(); i++) {
if (i == 0) {
v.push_back({s[i] - 'a', 1});
continue;
}
if (s[i] == s[i - 1]) v[(int)v.size() - 1].second++;
else v.push_back({s[i] - 'a', 1});
}
// cout << v.size() <<endl;
int res = 0;
while (1) {
if (v.size() == 1 || v.size() == 0) break;
res++;
for (int i = 0; i < v.size(); i++)
if (i == 0 || i == v.size() - 1) v[i].second--;
else v[i].second -= 2;
vector<pii> t;
for (int i = 0; i < v.size(); i++) {
if (v[i].second <= 0) continue;
t.push_back(v[i]);
int j = i + 1;
while (j < v.size() && (v[j].first == v[i].first || v[j].second <= 0)) {
if (v[j].second > 0) t[t.size() - 1].second += v[j].second;
j++;
}
i = --j;
}
v = t;
}
cout << res << endl;
}
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int cas;
cas = 1;
while (cas--) work();
}
E. Coprocessor
题意:
给你一个有向图,n个节点,每个节点有权值1或者0,按照拓扑排序删点,如果遇到连续的删1操作(可以为1次),则需要动用机器,问最少用多少次机器。
思路:
贪心,先全删0,删到不能再删,再删1;再全删0,删到不能再删,再删1…如此往复,求得操作次数。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
constexpr int maxn = 100010;
vector<int> g[maxn];
int d[maxn];
int a[maxn];
void work() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= m; i++) {
int a, b;
cin >> a >> b;
a++, b++;
g[b].push_back(a);
d[a]++;
}
queue<int> q[2];
int res = 0, cnt = 0;
for (int i = 1; i <= n; i++) if (d[i] == 0) q[a[i]].push(i);
while (cnt != n) {
if (q[0].size()) {
while (q[0].size()) {
int t = q[0].front();
q[0].pop();
cnt++;
for (int i = 0; i < (int)g[t].size(); i++) {
int v = g[t][i];
d[v]--;
if (d[v] != 0) continue;
q[a[v]].push(v);
}
}
} else {
res++;
while (q[1].size()) {
int t = q[1].front();
q[1].pop();
cnt++;
for (int i = 0; i < (int)g[t].size(); i++) {
int v = g[t][i];
d[v]--;
if (d[v] != 0) continue;
q[a[v]].push(v);
}
}
}
}
cout << res << endl;
}
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int cas;
cas = 1;
while (cas--) work();
}
F. AND-permutations
题意:
给一个 n n n,构造两个n的全排列,第一个序列 p i ≠ i pi≠i pi=i且 p i pi pi & i = 0 i=0 i=0,第二个序列 p i ≠ i pi≠i pi=i且 p i pi pi & i ≠ 0 i≠0 i=0。
p i pi pi为 1 1 1到 n n n中间的值且 p i pi pi不能重复。
思路:
对于第一问:
当 n n n为奇数无解,因为当 n n n为奇数时,一定有 k k k位偶数, k + 1 k+1 k+1位奇数,那么一定有一个为奇数放在为奇数的 i i i上,其二进制最后一位的与运算不为 0 0 0。
当 n n n为偶数时,对于二进制位 11001 11001 11001的数,我们要找到对应的 00110 00110 00110,可以看出前者为 2 k + i 2^k+i 2k+i,后者为 2 k − i − 1 2^k-i-1 2k−i−1,对应枚举即可。
对于第二问:
当 n n n小于 6 6 6时,我们分析可知一定无解。
当 n n n为 6 6 6或者 7 7 7时,我们输出特定的解。
当 n n n为 2 2 2的幂时,一定无解,因为对于最后一位 i i i,也就是 2 2 2的 n n n次幂,其上放的数一定小于 2 2 2的 n n n次幂,对应的二进制比 2 2 2的 n n n次幂短,运算后一定为 0 0 0,因为最高位此数为 0 0 0,其余位 i i i上的二进制为 0 0 0。
当
n
n
n不为
2
2
2的幂时,我们把
1
1
1到
n
n
n分为若干组:
1
1
1到
7
7
7一组,
8
8
8到
15
15
15一组
.
.
.
...
...
2
k
2^k
2k到
2
k
+
1
−
1
2^{k+1}-1
2k+1−1一组,余下的一组。
对于第一组,我们输出特定的解,对于剩余组,我们任意输出,只要满足
p
i
pi
pi不等于
i
i
i即可,因为一定在最高位都为
1
1
1,所以与运算一定不为
0
0
0。
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int vis[MAXN];
int main() {
int n, y = 1;
scanf("%d", &n);
while ((y << 1) <= n) y <<= 1;
if (n & 1) puts("NO");
else {
puts("YES");
int t = y;
for (int i = n; i >= 1; i--) {
if (t > i) t >>= 1;
if (!vis[i]) {
int x = t - (i - t) - 1;
vis[i] = x;
vis[x] = i;
}
}
for (int i = 1; i <= n; i++) printf("%d ", vis[i]);
puts("");
}
if (n == y || n < 6) puts("NO");
else {
puts("YES");
if (n == 6) puts("3 6 2 5 1 4");
else {
printf("7 3 6 5 1 2 4 ");
for (int i = 8; i <= n;) {
int j = min(i << 1, n + 1);
for (int k = i; k < j - 1; k++) printf("%d ", k + 1);
printf("%d ", i);
i = j;
}
}
}
return 0;
}