A. Prison Break
题意:有一个大小为a * b的网格,问至少拆除几条边可以使从任何一个格子都能出去
几个格子就拆几条边
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 1e6 + 7;
const int M = 2e6 + 7;
int main() {
int t, n, m;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
cout << n * m << '\n';
}
return 0;
}
B. Restore Modulo(思维)
题意:
给定一个序列,问是否能找到一组m、c使得
(1)
(2)
若不存在,输出-1,否则求一组m最大的解,若m可以无限大输出0。
思路:
(1)若数列等差,m可以无限大(具体证明不会
(2)每一个的位置,
即为c,并且所有
应该相同,否则不可能
(3)每一个的位置肯定受到了%m的影响,令
,所有b应该相同,否则不可能
(4)b + c 即为m,c = (c + m) % m,判断一下此时m是否大于等于原序列中的最大值,若是则不可能。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 1e5 + 7;
const int M = 2e6 + 7;
ll a[N];
int main() {
int t, n;
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
bool f1 = 1, f2 = 0;
ll c = -1, m = -1, maxx = -1;
for(int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
maxx = max(maxx, a[i]);
if(f1 && i > 1 && a[i] != a[i - 1]) f1 = 0;
if(!f2 && i > 1 && a[i] == a[i - 1]) f2 = 1;
}
if(f1) {
printf("0\n");
continue;
}
if(f2) {
printf("-1\n");
continue;
}
bool flag = 1;
for(int i = 2; i <= n; ++i) {
if(a[i] > a[i - 1]) {
if(c == -1) c = a[i] - a[i - 1];
else {
if(a[i] - a[i - 1] != c) {
flag = 0;
break;
}
}
}
}
if(!flag) {
printf("-1\n");
continue;
}
for(int i = 2; i <= n; ++i) {
if(a[i] < a[i - 1]) {
if(m == -1) m = a[i - 1] - a[i];
else {
if(a[i - 1] - a[i] != m) {
flag = 0;
break;
}
}
}
}
if(!flag) {
printf("-1\n");
continue;
}
if(c == -1 || m == -1) {
printf("0\n");
continue;
}
m += c;
c = (c + m) % m;
if(maxx >= m) printf("-1\n");
else printf("%lld %lld\n", m, c);
}
return 0;
}
C. Basic Diplomacy(贪心 || 网络流)
题意:有m天,每天都要选择一个人,现在给出每天可以选择的人有哪些,每个人不能被选超过 天,输出一种选法。
贪心:
最多只有一个人超过 天,可以先给每一天随机分配一个人,如果某个人的邀请次数超过限制条件,把这一天换一个人即可,最后判断是否合法。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 1e5 + 7;
const int M = 2e6 + 7;
vector<int>mp[N];
int n, m, ans[N], cnt[N];
int main() {
int t, k, a;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++i) mp[i].clear();
for(int i = 1; i <= n; ++i) cnt[i] = 0;
for(int i = 1; i <= m; ++i) {
scanf("%d", &k);
for(int j = 1; j <= k; ++j) {
scanf("%d", &a);
mp[i].emplace_back(a);
}
ans[i] = a;
cnt[a]++;
}
for(int i = 1; i <= m; ++i) {
if(cnt[ans[i]] <= (m + 1) / 2) continue;
int siz = mp[i].size();
for(int j = 0; j < siz; ++j) {
if(cnt[mp[i][j]] < (m + 1) / 2) {
cnt[ans[i]]--;
cnt[mp[i][j]]++;
ans[i] = mp[i][j];
break;
}
}
}
bool flag = 1;
for(int i = 1; i <= n; ++i) {
if(cnt[i] > (m + 1) / 2) {
flag = 0;
break;
}
}
if(!flag) printf("NO\n");
else {
printf("YES\n");
for(int i = 1; i <= m; ++i) {
if(i > 1) printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
}
return 0;
}
网络流做法:
天数:1~m,人:m + 1~m + n
超级源点和每一天连边,流量为1
每天和当天可以选择的人连边,流量为1
每人和超级汇点连边,流量为
注意路径的输出
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 2e5 + 7;
const int M = 2e6 + 7;
int head[N], dis[N], tot, ans[N];
struct Edge {
int to, next, cap, flow;
}edge[M];
void init() {
tot = 2;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w, int rw = 0) {
edge[tot].to = v;
edge[tot].cap = w;
edge[tot].flow = 0;
edge[tot].next = head[u];
head[u] = tot++;
edge[tot].to = u;
edge[tot].cap = rw;
edge[tot].flow = 0;
edge[tot].next = head[v];
head[v] = tot++;
}
int Q[N];
int dep[N], cur[N], sta[N];
bool bfs(int s, int t, int n) {
int fron = 0, tail = 0;
memset(dep, -1, sizeof(dep[0]) * (n + 1));
dep[s] = 0;
Q[tail++] = s;
while(fron < tail) {
int u = Q[fron++];
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if(edge[i].cap > edge[i].flow && dep[v] == -1) {
dep[v] = dep[u] + 1;
if(v == t) return true;
Q[tail++] = v;
}
}
}
return false;
}
int dinic(int s, int t, int n) {
int maxflow = 0;
while(bfs(s, t, n)) {
for(int i = 0; i <= n; ++i) cur[i] = head[i];
int u = s, tail = 0;
while(cur[s] != -1) {
if(u == t) {
int tp = inf;
for(int i = tail - 1; i >= 0; --i)
tp = min(tp, edge[sta[i]].cap - edge[sta[i]].flow);
maxflow += tp;
for(int i = tail - 1; i >= 0; --i) {
edge[sta[i]].flow += tp;
edge[sta[i] ^ 1].flow -= tp;
if(edge[sta[i]].cap - edge[sta[i]].flow == 0)
tail = i;
}
u = edge[sta[tail] ^ 1].to;
}
else if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) {
sta[tail++] = cur[u];
u = edge[cur[u]].to;
}
else {
while(u != s && cur[u] == -1)
u = edge[sta[--tail] ^ 1].to;
cur[u] = edge[cur[u]].next;
}
}
}
return maxflow;
}
int main() {
int t, n, m, a, k;
scanf("%d", &t);
while(t--) {
init();
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++i) {
scanf("%d", &k);
for(int j = 1; j <= k; ++j) {
scanf("%d", &a);
addedge(i, a + m, 1);
}
}
int s = n + m + 1, t = n + m + 2;
for(int i = 1; i <= m; ++i) addedge(s, i, 1);
for(int i = m + 1; i <= m + n; ++i) addedge(i, t, (m + 1) / 2);
int maxflow = dinic(s, t, t);
if(maxflow != m) {
printf("NO\n");
continue;
}
printf("YES\n");
for(int i = 1; i <= m; ++i) {
for(int j = head[i]; ~j; j = edge[j].next) {
if(edge[j].to != i && edge[j].to != s && edge[j].to != t && edge[j].flow) {
if(edge[j].to > m) {
ans[i] = edge[j].to - m;
break;
}
}
}
}
for(int i = 1; i <= m; ++i) {
if(i > 1) printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
return 0;
}