您的位置:首页 > 其它

CCPC-Wannafly Summer Camp 2019 Day1

2019-07-24 00:01 183 查看
原文链接:http://www.cnblogs.com/Mrzdtz220/p/11235297.html

 

A - Jzzhu and Cities

CodeForces - 449B

题意:n座城市,m条路,k条铁路啥的吧,然后要求最多能删多少条铁路保持1到$n$的最短路不变。

思路:因为铁路是从1出发的。所以能删的铁路有该铁路长度不等于1到该节点的最短路的,相等的时候,如果该节点的入度非1,也可以删去。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <functional>
#define ll long long
#define pb push_back
#define P pair<ll, int>
using namespace std;

template<typename T>
inline void read(T &x) {
x = 0; T f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
x *= f;
}

const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 7;
vector<P> G
;
bool done
;
struct Po { int v; ll c; } po
;
int n, m, k;
int in
;
ll d
;

void dijkstra(ll *d, int s) {
for (int i = 1; i <= n; i++) d[i] = INF, done[i] = 0;
d[s] = 0;
priority_queue<P, vector<P>, greater<P> > que;
que.push(P(0, s));
while (!que.empty()) {
auto p = que.top(); que.pop();
int u = p.second;
if (done[u]) continue;
done[u] = 1;
for (auto pp: G[u]) {
int v = pp.second;
if (d[v] > d[u] + pp.first) {
in[v] = 1;
d[v] = d[u] + pp.first;
que.push(P(d[v], v));
} else if (d[v] == d[u] + pp.first) {
in[v]++;
}
}
}
}

int main() {
read(n); read(m); read(k);
while (m--) {
int u, v; ll c;
read(u); read(v); read(c);
G[u].pb(P(c, v));
G[v].pb(P(c, u));
}
for (int i = 1; i <= k; i++) {
read(po[i].v); read(po[i].c);
G[1].pb(P(po[i].c, po[i].v));
G[po[i].v].pb(P(po[i].c, 1));
}
dijkstra(d, 1);
memset(done, 0, sizeof(done));
int ans = 0;
for (int i = 1; i <= k; i++) {
int v = po[i].v;
if (d[v] < po[i].c) ans++;
else if (d[v] == po[i].c && in[v] > 1) {
in[v]--;
ans++;
}
}
printf("%d\n", ans);
return 0;
}
Vi 3ff7 ew Code

 

B - Phillip and Trains

CodeForces - 585B

题意:$3 \times n$的方格,一个人在最左边的一个起始位置,先向右走一步,再选择向上、不动、向下走一步。然后轮到所有火车往左走两步。问这个人能否安全走到最右边那列。

思路:BFS。当前位置先往右走一步,再枚举上中下三个位置,因为火车向左走两步,可以等同于人往右走两步,所以就是判断人能不能往后走两格。

#include <cstdio>
#include <algorithm>
#include <cctype>
#include <queue>
#include <cstring>
#define P pair<int, int>
using namespace std;

const int N = 110;
int n, k;
char s[5]
;
bool ans;
bool mp[5]
;

bool bfs(int sx) {
queue<pair<int, int> > que;
que.push(P(sx, 1));
while (!que.empty()) {
P p = que.front(); que.pop();
int x = p.first, y = p.second;
if (isalpha(s[x][++y])) continue;
if (y >= n) return true;
for (int i = -1; i <= 1; i++) {
int dx = x + i;
if (dx <= 0 || dx > 3) continue;
if (isalpha(s[dx][y]) || isalpha(s[dx][y + 1]) || isalpha(s[dx][y + 2]) || s[dx][y + 2] == 1) continue;
int dy = y + 2;
if (dy >= n) return true;
s[dx][dy] = 1;
que.push(P(dx, dy));
}
}
return false;
}

int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &k);
memset(s, 0, sizeof(s));
for (int i = 1; i <= 3; i++) scanf("%s", s[i] + 1);
int sx = 0;
for (int i = 1; i <= 3; i++)
if (s[i][1] == 's')
sx = i;
if (bfs(sx)) puts("YES");
else puts("NO");
}
return 0;
}
View Code

 

C - A Mist of Florescence

CodeForces - 989C

借鉴的别人的思路。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

char s[55][55];

int main() {
int a, b, c, d;
scanf("%d%d%d%d", &a, &b, &c, &d);
a--; b--;
for (int i = 0; i < 50; i++)
for (int j = 0; j < 50; j++)
if (i < 25) s[i][j] = 'A';
else s[i][j] = 'B';
for (int i = 0; i < 24; i += 2)
for (int j = 0; j < 50; j += 2) {
if (b) s[i][j] = 'B', b--;
else if (d) s[i][j] = 'D', d--;
}
for (int i = 26; i < 50; i += 2)
for (int j = 0; j < 50; j += 2) {
if (a) s[i][j] = 'A', a--;
else if (c) s[i][j] = 'C', c--;
}
printf("50 50\n");
for (int i = 0; i < 50; i++) puts(s[i]);
return 0;
}
View Code

 

D - Unbearable Controversy of Being

CodeForces - 489D

题意:给一个有向图,找出$\left( a,b,c,d\right)$的对数满足题面的图。

思路:暴力枚举$a$,$c$然后组合数搞搞。

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;

const int N = 3031;
bool mp

;
vector<int> G
;

template<typename T>
inline void read(T &x) {
x = 0; T f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
x *= f;
}

int main() {
//freopen("in.txt", "r", stdin);
int n, m;
read(n); read(m);
while (m--) {
int u, v;
read(u); read(v);
mp[u][v] = 1;
G[u].push_back(v);
}
int ans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (i != j) {
int res = 0;
for (auto temp: G[i])
if (temp != i && temp != j && mp[temp][j]) res++;
ans += res * (res - 1) / 2;
}
printf("%d\n", ans);
return 0;
}

/*
input
5 4
1 2
2 3
1 4
4 3
output
1
input
4 12
1 2
1 3
1 4
2 1
2 3
2 4
3 1
3 2
3 4
4 1
4 2
4 3
output
12
*/
View Code

 

E - Igor In the Museum

CodeForces - 598D

#include <cstdio>
#include <algorithm>
#include <map>
#include <cstring>
#define P pair<int, int>
using namespace std;

const int N = 1010;
bool vis

;
int cnt, n, m;
int ans[N * N];
int mp

;
char mpp

;
const int dir[4][2] = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

void dfs(int x, int y, int now) {
vis[x][y] = 1;
mp[x][y] = now;
for (int i = 0; i < 4; i++) {
int dx = x + dir[i][0], dy = y + dir[i][1];
if (dx <= 0 || dy <= 0 || dx > n || dy > m) continue;
if (!vis[dx][dy]) {
if (mpp[dx][dy] == '*') ans[now]++;
else dfs(dx, dy, now);
}
}
}

int main() {
int k;
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++) scanf("%s", mpp[i] + 1);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
if (mpp[i][j] == '.' && !vis[i][j]) {
dfs(i, j, ++cnt);
}
}
while (k--) {
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", ans[mp[x][y]]);
}
return 0;
}
View Code

 

F - The Child and Toy

CodeForces - 437C

贪心优先处理权值大的。只考虑两个的情况,优先处理一个会使答案加上另一个的权值,所以先处理大的会比处理小的更优。这个能推广到多个数。

#include <cstdio>
#include <algorithm>
#include <vector>
#define ll long long
#define pb push_back
using namespace std;

template<typename T>
inline void read(T &x) {
x = 0; T f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
x *= f;
}

const int N = 1010;
struct P {
ll v; int u;
bool operator < (const P &rhs) const {
return v > rhs.v;
}
} p
;
int n, a
, m;
bool vis
;
vector<int> G
;

int main() {
read(n); read(m);
for (int i = 1; i <= n; i++) {
read(a[i]);
p[i].u = i; p[i].v = a[i];
}
while (m--) {
int u, v;
read(u); read(v);
G[u].pb(v); G[v].pb(u);
}
sort(p + 1, p + n + 1);
ll ans = 0;
for (int i = 1; i <= n; i++) {
int u = p[i].u;
vis[u] = 1;
for (auto v: G[u])
if (!vis[v]) ans += a[v];
}
printf("%lld\n", ans);
return 0;
}
View Code

 

G - New Year Permutation

CodeForces - 500B

题意:给一个排列,以及代表哪些位置能交换的矩阵,问字典序最小的排列长啥样。

思路:现在一想不就是Floyd传递闭包吗。写的时候没想起来,就dfs处理一下连通块之类的。然后就可以贪心去排了

#include <cstdio>
#include <algorithm>
using namespace std;

template<typename T>
inline void read(T &x) {
x = 0; T f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
x *= f;
}

const int N = 330;
int pos
, a
;
char s

;
int mp

;
int block
, n, cnt;

void dfs(int u, int c) {
//printf("%d %d\n", u, c);
block[u] = c;
for (int i = 1; i <= n; i++) {
if (s[u][i] == '1' && !block[i]) {
dfs(i, c);
}
}
}

int main() {
//freopen("in.txt", "r", stdin);
read(n);
for (int i = 1; i <= n; i++) {
read(a[i]);
pos[a[i]] = i;
}
for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
for (int i = 1; i <= n; i++)
if (!block[i]) dfs(i, ++cnt);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
mp[i][j] = (block[i] == block[j]) ? 1 : 0;
}
}
for (int i = n; i > 1; i--) {
for (int j = n; j > pos[i]; j--) {
if (mp[pos[i]][j] && a[j] < i) {
//printf("%d %d\n", pos[i], j);
int temp = a[j];
swap(a[pos[i]], a[j]);
swap(pos[i], pos[temp]);
break;
}
}
}
for (int i = 1; i <= n; i++) printf("%d%c", a[i], " \n"[i == n]);
return 0;
}

/*
input
7
5 2 4 3 6 7 1
0001001
0000000
0000010
1000001
0000000
0010000
1001000
output
1 2 4 3 6 7 5
input
5
4 2 1 5 3
00100
00011
10010
01101
01010
output
1 2 3 4 5
*/
View Code

 

H - Alyona and the Tree

CodeForces - 682C

题意:给一棵树,如果存在一个叶子到它的一个祖先的距离大于它的权值,则该叶子应该删去,问最少需要删多少节点。

思路:两遍dfs,第一次处理出每个节点子树的节点数、该节点到1的距离$d$和从1到该节点的前缀距离中的最小值$mn$,$d-mn$能得到该节点到所有祖先中的最大距离,然后在dfs判断当前该节点是否要删即可。

#include <cstdio>
#include <algorithm>
#include <vector>
#define ll long long
#define P pair<int, ll>
#define pb push_back
using namespace std;

template<typename T>
inline void read(T &x) {
x = 0; T f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
x *= f;
}

const int N = 1e5 + 7;
ll dis
, a
, mm
;
int n, sz
, ans;
vector<P> G
;

void dfs1(int u, int pre) {
sz[u] = 1;
for (int i = 0; i < G[u].size(); i++) {
P p = G[u][i];
if (p.first == pre) continue;
dis[p.first] = dis[u] + p.second;
mm[p.first] = min(mm[u], dis[p.first]);
dfs1(p.first, u);
sz[u] += sz[p.first];
}
}

void dfs2(int u, int pre) {
for (int i = 0; i < G[u].size(); i++) {
P p = G[u][i];
if (p.first == pre) continue;
if (dis[p.first] - mm[p.first] > a[p.first]) {
ans += sz[p.first];
continue;
}
dfs2(p.first, u);
}
}

int main() {
read(n);
for (int i = 1; i <= n; i++) read(a[i]);
for (int i = 2; i <= n; i++) {
int u; ll c;
read(u); read(c);
G[u].pb(P(i, c));
G[i].pb(P(u, c));
}
dfs1(1, 1);
dfs2(1, 1);
printf("%d\n", ans);
}
View Code

 

I - Network Safety

CodeForces - 1039C

 思路自https://www.cnblogs.com/DeaphetS/p/9599587.html

 

J - Resort

CodeForces - 350B

思路:写了个类似于记忆化的东西,懒得想太多了。

#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;

template<typename T>
inline void read(T &x) {
x = 0; T f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
x *= f;
}

const int N = 1e5 + 10;
int dp
, a
, to
;
bool is
;
int top, st
, out
;
vector<int> G
;

int DP(int u) {
if (dp[u] != -1) return dp[u];
int &ans = dp[u];
ans = 1;
int v = to[u];
if (v && !is[v] && out[v] == 1) ans = DP(v) + 1;
return ans;
}

int main() {
//freopen("in.txt", "r", stdin);
memset(dp, -1, sizeof(dp));
int n;
read(n);
int cnt = 0;
for (int i = 1; i <= n; i++) {
int x; read(x);
if (x) a[++cnt] = i, is[i] = 1;
}
//for (int i = 1; i <= cnt; i++) printf("%d%c", a[i], " \n"[i == cnt]);
for (int i = 1; i <= n; i++) {
int x; read(x);
if (!x) continue;
out[x]++;
to[i] = x;
}
int ans = 0, id = 0;
for (int i = 1; i <= cnt; i++) {
int res = DP(a[i]);
if (res > ans) {
id = a[i];
ans = res;
}
}
printf("%d\n", ans);
st[++top] = id;
id = to[id];
for (; id && !is[id] && out[id] == 1; id = to[id]) st[++top] = id;
while(top) printf("%d%c", st[top], " \n"[top == 1]), --top;
}

/*

Input
5
0 0 0 0 1
0 1 2 3 4
Output
5
1 2 3 4 5
Input
5
0 0 1 0 1
0 1 2 2 4
Output
2
4 5
Input
4
1 0 0 0
2 3 4 2
Output
1
1
*/
View Code

 

K - Royal Questions

CodeForces - 875

题意:王子和公主的二分图匹配,求最大收

思路:数据范围小可以二分图匹配搞搞,但是这数据范围太大了。注意到一个公主与两个王子连边的权值是一样大的,就可以不考虑这个公主了,只考虑两个王子之间有一条边。

魔改一下kruskal,边按权值从大到小排序,只有当两个点都被选中过的时候,才不能继续选,两个点在一个并查集里同理。

#include <cstdio>
#include <algorithm>
using namespace std;

template<typename T>
inline void read(T &x) {
x = 0; T f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
x *= f;
}

const int N = 2e5 + 10;

struct E {
int a, b, w;
bool operator < (const E &rhs) const {
return w > rhs.w;
}
} e
;

int fa
, p
;

int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); }

int main() {
//freopen("in.txt", "r", stdin);
int n, m;
read(n); read(m);
for (int i = 1; i <= m; i++) {
read(e[i].a);
read(e[i].b);
read(e[i].w);
}
sort(e + 1, e + m + 1);
for (int i = 1; i <= n; i++) fa[i] = i;
int ans = 0;
for (int i = 1; i <= m; i++) {
int x = getfa(e[i].a), y = getfa(e[i].b);
if (x != y) {
if (p[x] && p[y]) continue;
p[x] = p[x] | p[y];
fa[y] = x;
ans += e[i].w;
} else if (!p[x]) {
p[x] = 1;
ans += e[i].w;
}
}
printf("%d\n", ans);
return 0;
}
View Code

 

L - Love Triangle

CodeForces - 939A

#include <cstdio>
#include <vector>
#include <queue>
#define eb emplace_back
using namespace std;

const int N = 5050;
int to
;

int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int x; scanf("%d", &x);
to[i] = x;
}
for (int i = 1; i <= n; i++) {
if (to[to[to[i]]] == i) {
puts("YES");
return 0;
}
}
puts("NO");
return 0;
}
View Code

 

M - Bakery

CodeForces - 707B

题意:$n$座城市,$m$条边,$k$个关键点,问能否找一个非关键点和一个关键点,它们之间的距离最小。

思路:刚开始以为要$k$次最短路???过一会才意识过来,这个最小距离只能是题目给的边。然后找一下就OK了。

#include <cstdio>
#include <algorithm>
using namespace std;

template<typename T>
inline void read(T &x) {
x = 0; T f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
x *= f;
}

const int N = 1e5 + 7;
const int INF = 0x3f3f3f3f;
bool pos
;
struct P { int u, v, c; } p
;

int main() {
int n, m, k;
read(n); read(m); read(k);
for (int i = 1; i <= m; i++) {
read(p[i].u); read(p[i].v); read(p[i].c);
}
for (int i = 1; i <= k; i++) {
int x; read(x);
pos[x] = 1;
}
int ans = INF;
for (int i = 1; i <= m; i++)
if (pos[p[i].u] + pos[p[i].v] == 1) ans = min(ans, p[i].c);
if (ans == INF) ans = -1;
printf("%d\n", ans);
return 0;
}
View Code

 

N - News Distribution

CodeForces - 1167C

思路:又是一道被我误伤成dfs的题,但貌似我的代码跑得更快?hhh

#include <cstdio>
#include <vector>
#define pb push_back
using namespace std;

const int N = 1e6 + 10;
vector<int> G
;
int vis
, cnt, ans
, n;

void dfs(int u) {
vis[u] = cnt;
if (u <= n) ans[cnt]++;
for (auto v: G[u]) {
if (!vis[v]) {
dfs(v);
}
}
}

int main() {
int m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int k; scanf("%d", &k);
while (k--) {
int x;
scanf("%d", &x);
G[x].pb(i + n);
G[i + n].pb(x);
}
}
for (int i = 1; i <= n; i++) {
if (!vis[i]) {
cnt++;
dfs(i);
}
printf("%d%c", ans[vis[i]], " \n"[i == n]);
}
return 0;
}
View Code

 

O - NP-Hard Problem

CodeForces - 687A

思路:二分图染色

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define eb emplace_back
using namespace std;

template<typename T>
inline void read(T &x) {
x = 0; T f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
x *= f;
}

const int N = 1e5 + 7;
int n, m, color
;
vector<int> G
, ans[2];

bool dfs(int u, int c) {
color[u] = c;
ans[c == 1].eb(u);
for (auto v: G[u]) {
if (!color[v] && !dfs(v, -c)) return false;
else if (color[v] == color[u]) return false;
}
return true;
}

int main() {
read(n); read(m);
while (m--) {
int u, v;
read(u); read(v);
G[u].eb(v); G[v].eb(u);
}
bool res = 1;
for (int i = 1; i <= n; i++) {
if (!color[i]) {
res = dfs(i, 1);
if (!res) {
puts("-1");
return 0;
}
}
}
int sz = ans[1].size();
printf("%d\n", sz);
for (int i = 0; i < sz; i++) printf("%d%c", ans[1][i], " \n"[i == sz - 1]);
sz = ans[0].size();
printf("%d\n", sz);
for (int i = 0; i < sz; i++) printf("%d%c", ans[0][i], " \n"[i == sz - 1]);
return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Mrzdtz220/p/11235297.html

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: