http://codeforces.com/contest/1287

B. Hyperset

 

题意:给出n个字符串,要求若三个字符串每一列的三个字母都不同或者都相同,则可以放一起,求最多凑出几个集合。

若已知两个字符串,则第三个字符串就是确定的。map找到即可。

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
35
36
37
38
#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 10;
int n, k;
map<string,int>mp;
string s[maxn];
int ans;
int vis[30];
char oth(char a, char b) {
int x = 'S' - 'A', y = 'E' - 'A', z = 'T' - 'A';
vis[x] = vis[y] = vis[z] = 0;
vis[a - 'A'] = 1; vis[b - 'A'] = 1;
if (!vis[x])return 'S';
else if (!vis[y])return 'E';
else return 'T';
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
cin >> s[i];
mp[s[i]] = i;
}
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
string tmp;
for (int p = 0; p < k; p++) {
if (s[i][p] == s[j][p])tmp.push_back(s[i][p]);
else tmp.push_back(oth(s[i][p], s[j][p]));
}
if (mp.count(tmp) && mp[tmp] > j)ans++;
}
}
printf("%d\n", ans);
return 0;
}

 

C. Garland

 

题意:给定一个排列,其中有一些缺失了。要求填入,使得相邻奇偶性不同的数对个数最少。输出最少对数。

dp

dp[i] [j] [k] 表示第 i 个,到第 i 个共有 j 个奇数,第 i 个数是奇数/偶数。

则分原排列中第 i 个是否已经确定讨论。

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
35
36
#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 10;
int n;
int a[maxn];
int dp[110][110][110];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)scanf("%d", &a[i]);
memset(dp, 0x3f, sizeof(dp));
if (a[1] == 0)dp[1][0][0] = dp[1][1][1] = 0;
else dp[1][(a[1] & 1)][(a[1]) & 1] = 0;
for (int i = 2; i <= n; i++) {
if (a[i] == 0) {
for (int j = 1; j <= i; j++)
dp[i][j][1] = min(dp[i - 1][j - 1][1], dp[i - 1][j - 1][0] + 1);
for (int j = 0; j <= i; j++)
dp[i][j][0] = min(dp[i - 1][j][0], dp[i - 1][j][1] + 1);
}
else {
if (a[i] & 1) {
for (int j = 1; j <= i; j++)
dp[i][j][1] = min(dp[i - 1][j - 1][1], dp[i - 1][j - 1][0] + 1);
}
else {
for (int j = 0; j <= i; j++)
dp[i][j][0] = min(dp[i - 1][j][0], dp[i - 1][j][1] + 1);
}
}
}
printf("%d\n", min(dp[n][n / 2 + (n & 1)][0], dp[n][n / 2 + (n & 1)][1]));
return 0;
}

 

D. Numbers on Tree

 

题意:给定一棵树,构造结点值。满足结点的子树中结点值小于该结点的结点个数等于规定值。

dfs

后序遍历,保证先处理完子节点。

每次直接把当前节点插入到规定位置,这样做是可行的。因为属于不同的子树中的结点被处理时会先用自己的子树把vector更新,使得vector的最前面一串一定都是自己的子树。

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
35
36
37
38
39
40
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 10;
int n;
int p[maxn], c[maxn];
int sz[maxn];
vector<int>G[maxn];
int rt;
vector<int>vc;
void dfs(int u) {
sz[u] = 1;
for (int v : G[u]) {
dfs(v);
sz[u] += sz[v];
}
if (sz[u] <= c[u]) {
puts("NO");
exit(0);
}
vc.insert(vc.begin() + c[u], u);
}
int ans[maxn];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &p[i], &c[i]);
if (p[i] == 0)rt = i;
else G[p[i]].push_back(i);
}
dfs(rt);
puts("YES");
for (int i = 0; i < n; i++) {
ans[vc[i]] = i + 1;
}
for (int i = 1; i <= n; i++)printf("%d ", ans[i]);
printf("\n");
return 0;
}