https://ac.nowcoder.com/acm/contest/5205/

A. 牛妹的游戏

题意:平面上有n个点,完全图中的每条边边被红方或蓝方占领,给出了蓝方占领的边。问是否有三条同一阵营的边连成三角形。

由拉塞姆结论得到如果平面上大于等于6个点,那么必定有至少一方形成三角形。

假设AB,AC,AD属于蓝方,则BC,BD,CD一定要属于红方,否则已经有三角形了。但是BC,BD,CD又形成了三角形。所以得证。

那么只要在5个点以内暴力判断一下即可。

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
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
int T;
int n, m;
int mp[100][100];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
memset(mp, 0, sizeof(mp));
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
if (n <= 5)mp[u][v] = mp[v][u] = 1;
}
if (n > 5) { puts("yes"); continue; }
bool flg = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) {
for (int k = 1; k < j; k++) {
if (mp[i][j] == mp[j][k] && mp[j][k] == mp[i][k])flg = 1;
}
}
}
puts(flg ? "yes" : "no");
}
return 0;
}

 

B. 病毒扩散

题意:初始时原点有一个病毒,每个病毒每秒向上或右扩散一个,问在第 t 秒点 (x,y) 有几个病毒。

有点类似路径数,一定和排列组合有关,打表或者推公式找规律。

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
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
int T;
int x, y, t;
ll CC[5010][5010];
ll C(int n, int k) {
if (n < 0 || k < 0 || n < k)return 0;
return CC[n][k];
}
int main() {
scanf("%d", &T);
for (int i = 0; i <= 5000; i++)CC[i][0] = CC[i][i] = 1ll;
for (int i = 0; i <= 5000; i++) {
for (int j = 0; j < i; j++)
CC[i][j] = (CC[i - 1][j] + CC[i - 1][j - 1]) % mod;
}
while (T--) {
scanf("%d%d%d", &x, &y, &t);
printf("%lld\n", C(t, x)*C(t - x, y) % mod);
}
return 0;
}

 

C. 牛牛染颜色

 

题意:树上节点染黑白色,任意两个黑节点的LCA必须是黑的。问方案数。

树形dp

dp[u][0/1]dp[u][0/1] 表示u染白/黑色的子树的方案数。

父节点染黑色,则子节点随便什么颜色;

父节点染白色,则只能子树中所有节点都是白色或者有一棵子树随便染,其它都要全白。这里所有节点都是白色的情况被重复计算了,所以要减去 儿子个数-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
35
36
37
38
39
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
int n;
int to[N << 1], st[N], nx[N << 1], tot, d[N];
inline void add(int u, int v) { to[++tot] = v, nx[tot] = st[u], st[u] = tot, d[u]++; }
ll dp[N][2], sn[N];
void dfs(int u, int _fa) {
if (d[u] == 1 && u != 1) {
dp[u][0] = dp[u][1] = 1ll;
return;
}
dp[u][1] = 1ll;
for (int i = st[u]; i; i = nx[i]) {
int v = to[i];
if (v == _fa)continue;
sn[u]++;
dfs(v, u);
dp[u][1] = dp[u][1] * (dp[v][1] + dp[v][0]) % mod;
dp[u][0] = (dp[u][0] + dp[v][0] + dp[v][1]) % mod;
}
dp[u][0] = (dp[u][0] + mod - sn[u] + 1) % mod;
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
}
dfs(1, 0);
printf("%lld\n", (dp[1][0] + dp[1][1]) % mod);
return 0;
}

 

D. 牛牛的呱数

 

题意:有n个数字,每个数字有无限多个,选出几个数字拼起来,问最短的是p的倍数的数。

对于一个数字只要维护它的长度,以及它模p的余数即可,把两个数字拼起来就是长度相加,余数为10的前面的数长度幂次乘以前一个数的余数,再加上后一个数的余数再取模。

维护10的长度幂次,以及模p的余数,在这两个相同的情况下长度最短,然后bfs。

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
41
42
43
44
45
46
47
48
49
50
51
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
int n, p;
int val[N], pw[N], le[N];
char s[N];
int d[300][300];
typedef pair<int, int>pii;
typedef pair<int, pii>ppii;
int bfs() {
priority_queue<ppii, vector<ppii>, greater<ppii> >q;
memset(d, 0x3f, sizeof(d));
for (int i = 1; i <= n; i++) {
if (d[pw[le[i]]][val[i]] > le[i]) {
d[pw[le[i]]][val[i]] = le[i];
q.push(ppii(d[pw[le[i]]][val[i]], pii(pw[le[i]], val[i])));
}
}
while (!q.empty()) {
ppii t = q.top(); q.pop();
int di = t.first, x = t.second.first, y = t.second.second;
if (y == 0)return d[x][y];
if (di > d[x][y])continue;
for (int i = 1; i <= n; i++) {
int nx = x * pw[le[i]] % p, ny = (y*pw[le[i]] % p + val[i]) % p;
int nd = d[x][y] + le[i];
if (d[nx][ny] > nd) {
d[nx][ny] = nd;
q.push(ppii(d[nx][ny], pii(nx, ny)));
}
}
}
return -1;
}
int main() {
scanf("%d%d", &n, &p);
pw[0] = 1;
for (int i = 1; i <= 1000000; i++)pw[i] = pw[i - 1] * 10 % p;
for (int i = 1; i <= n; i++) {
scanf("%s", s);
le[i] = strlen(s);
for (int j = 0; s[j]; j++) {
val[i] = (val[i] * 10 + (s[j] - '0')) % p;
}
}
printf("%d\n", bfs());
return 0;
}