A.Set of Strings(Codeforces 544A)
思路
显然,若字符串中有不少于 k 个不同的字符,则一定能找到满足条件的分割方式。(因为允许只含有一个字符的子串)
代码
#include <bits/stdc++.h>
using namespace std;
int k, vis[30];
string s, sub;
vector <int> v;
int main() {
cin >> k >> s;
for(int i = 0; i < s.size(); i++) {
if(vis[s[i]-'a'] == 0) {
vis[s[i]-'a'] = 1;
v.push_back(i);
}
}
if(v.size() < k) puts("NO");
else {
puts("YES");
for(int i = 0; i < k; i++) {
if(i != k - 1) sub = s.substr(v[i], v[i+1] - v[i]);
else sub = s.substr(v[i], s.size() - v[i]);
cout << sub << endl;
}
}
return 0;
}
B.Sea and Islands(Codeforces 544B)
思路
这是一道构造的题目。由于是构造,所以只需要找到构造的特例就行。首先,由国际象棋的棋盘可以联想到,
代码
#include <cstdio>
int n, k;
int main() {
scanf("%d%d", &n, &k);
if(2 * k - 1 > n * n) {
puts("NO");
}
else {
puts("YES");
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(k > 0 && ((i ^ j) & 1) == 0) {
putchar('L');
k--;
}
else {
putchar('S');
}
}
puts("");
}
}
return 0;
}
C.Writing Code(Codeforces 544C)
思路
这种有一定资源限制求最优解或解的数量,或者说在每种状态下有超过一种的决策方案,但是不同的决策向量的子结构能转移到同一个状态的问题,通常能用动态规划解决。更具体地,通常能用背包思想解决。因为显然程序员i写的单行代码就是背包问题中的物品
i
。由于一个程序员写的代码行数没有数量限制,因此这是个完全背包问题。回忆一下,只有一种限制条件(二维)的完全背包的状态转移方程为
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 505;
int n, m, b, mod, ans, a[maxn], d[maxn][maxn];
int main() {
scanf("%d%d%d%d", &n, &m, &b, &mod);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
d[0][0] = 1;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
for(int k = a[i]; k <= b; k++) {
d[j][k] = (d[j][k] + d[j-1][k-a[i]]) % mod;
}
}
}
for(int k = 0; k <= b; k++) {
ans = (ans + d[m][k]) % mod;
}
printf("%d\n", ans);
return 0;
}
D.Destroying Roads(Codeforces 544D)
思路
若不考虑路径重合的话,
d[s1][t1]+d[s2][t2]
就应该是最后剩余道路的数量
num
(对任意的
x
和
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3010;
bool vis[maxn];
int n, m, u, v, s1, t1, l1, s2, t2, l2, tmp, ans;
int d[maxn][maxn];
vector <int> G[maxn];
void bfs(int s) {
queue <int> q;
q.push(s);
vis[s] = true;
d[s][s] = 0;
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(vis[v] == true) {
continue;
}
d[s][v] = d[s][u] + 1;
q.push(v);
vis[v] = true;
}
}
}
int main() {
scanf("%d%d", &n , &m);
for(int i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
scanf("%d%d%d", &s1, &t1, &l1);
scanf("%d%d%d", &s2, &t2, &l2);
for(int i = 1; i <= n; i++) {
memset(vis, 0, sizeof(vis));
bfs(i);
}
if(d[s1][t1] > l1 || d[s2][t2] > l2) {
puts("-1");
return 0;
}
ans = d[s1][t1] + d[s2][t2];
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(d[s1][i] + d[i][j] + d[j][t1] > l1) {
continue;
}
tmp = d[i][j] + d[s1][i] + d[j][t1];
if(d[s2][i] + d[i][j] + d[j][t2] <= l2) {
ans = min(ans, tmp + d[s2][i] + d[j][t2]);
}
if(d[s2][j] + d[i][j] + d[i][t2] <= l2) {
ans = min(ans, tmp + d[s2][j] + d[i][t2]);
}
}
}
printf("%d\n", m - ans);
return 0;
}
E.Remembering Strings(Codeforces 544E)
思路
这是一个从初始状态经过一系列操作得到目标状态,求最优解的问题。这样的问题适合用搜索或者动态规划解决。由于数据规模的原因,因此不能用搜索解决。分析问题后容易知道,因为行数的上限是20,而小写字母有26个,所以当某行不满足条件时总能通过将该行某列的字符改成别的字符或者将其它行某列的与该行该列相同的字符全部改成其它字符来使该行满足条件而不影响其他行。由于既不能搜索又不能贪心,而且数据量不是很大,所以直接将每行是否满足条件用1和0表示,于是能用一个二进制数表示所有行的状态,进行状态压缩的动态规划。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 20 + 1, INF = 1e9;
char s[maxn][maxn];
int n, m, Max, nn, x, y;
int d[1<<maxn], a[maxn][maxn], b[maxn][maxn], same[maxn][maxn];
int main() {
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) {
scanf("%s", s[i]);
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
scanf("%d", &a[i][j]);
}
}
// 预处理出b和same
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
Max = 0;
// 该列有多少与该字符相同的字符
for(int k = 0; k < n; k++) {
if(s[i][j] != s[k][j]) {
continue;
}
// 将相同字符的位置信息记录下来
same[i][j] |= (1 << k);
Max = max(Max, a[k][j]);
b[i][j] += a[k][j];
}
b[i][j] -= Max;
}
}
nn = 1 << n;
fill(d, d + nn, INF);
d[0] = 0;
for(int i = 0; i < nn; i++) {
// 查找一个不满足条件的行
for(int j = 0; j < n; j++) {
x = 1 << j;
if(x & i) {
continue;
}
// 查找一个要修改的列
for(int k = 0; k < m; k++) {
int y = same[j][k];
d[i|x] = min(d[i|x], d[i] + a[j][k]);
d[i|y] = min(d[i|y], d[i] + b[j][k]);
}
break;
}
}
printf("%d\n", d[nn-1]);
return 0;
}