AtCoder AGC038 題解
只寫了一部分QAQ。。。
剩下的坑後面再填吧。。。
A.01 Matrix
題目大意
要求構造一個的01矩陣,其中每行0或者1中較少者的數量恰好爲,每列0或1中較少者的數量恰好爲。求這樣一個矩陣。
分析
按如下方法構造即可:
參考代碼
#include <cstdio>
#include <algorithm>
using namespace std;
int main() {
#ifdef LOACL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int N, M, A, B;
scanf("%d %d %d %d", &N, &M, &A, &B);
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++)
if((i <= B && j <= A) || (i > B && j > A))
putchar('1');
else putchar('0');
putchar('\n');
}
return 0;
}
D.Unique Path
題目大意
給定條信息,每條信息要麼表示圖上之間只有一條簡單路徑或者多條路徑。求是否存在一個個點條邊的連通圖符合所有的信息。
分析
考慮給定的信息中的第一類,即只包含一條簡單路徑。
我們直接將這兩個點連起來就可以了。
這樣一來,整張圖目前就是一個森林。如果某個連通塊中有第二類信息出現,那麼是不合法的。
考慮將第二類信息加進來。
設已經產生了個連通塊,那麼最多需要在所有的連通塊之間連上邊,總邊數爲。
如果比這個還大的話,那麼就肯定無法構造出這個圖。
考慮最小的邊數。如果有第二類信息,那麼最小邊數爲,否則爲。如果比這還小的話,那麼也無法構造出這個圖。
參考代碼
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int Maxn = 1e5;
int N, K;
ll M;
vector<pair<int, int> > t;
int fa[Maxn + 5];
int find(int x) {
if(x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
int main() {
#ifdef LOACL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d %lld %d", &N, &M, &K);
for(int i = 1; i <= N; i++)
fa[i] = i;
for(int i = 1; i <= K; i++) {
int u, v, typ;
scanf("%d %d %d", &u, &v, &typ);
u++, v++;
if(typ == 0) {
int fu = find(u), fv = find(v);
if(fu != fv) fa[fu] = fv;
} else t.push_back(make_pair(u, v));
}
int cnt = 0;
for(int i = 1; i <= N; i++)
if(i == find(i)) cnt++;
ll mx = 1LL * cnt * (cnt - 1) / 2 + N - cnt;
if(mx < M) {
puts("No");
return 0;
}
ll mn = (t.empty() ? N - 1 : N);
if(mn > M) {
puts("No");
return 0;
}
for(int i = 0; i < (int)t.size(); i++)
if(find(t[i].first) == find(t[i].second)) {
puts("No");
return 0;
}
puts("Yes");
return 0;
}
F.Two Permutations
題目大意
給定兩個到的排列,現在可以將變成,或者變成,要求變換後仍然是一個到的排列。問變換後最多位置不相同的個數。
分析
我們先將置換分解成多個循環。那麼對於每個循環,要麼保持不變,要麼就全都變成。
而每個元素的選擇能夠互相影響,而這樣就很容易想到網絡流上去。
考慮將問題等價轉化:求最少的位置相同的個數。
考慮按照如下方式構圖:(如果我們用b表示選i,而c表示選Bi的話,那麼我們解方程就會解出負數)
列出方程:
考慮的不同關係所產生的代價:
- ,此時代價無論如何都是,直接減掉而不連邊;
- ,利用特殊值帶入方程,解得,其餘都是;
- ,利用特殊值,解得,其餘爲;
- ,利用特殊值,解得,其餘爲;
- ,利用特殊值,解得,其餘爲。
建圖跑網絡流最小割即可。
另外注意對於一個循環,我們建一個虛點,從虛點向循環裏的每個節點連一條容量爲的邊,表示無法將這些循環分開。
參考代碼
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int Maxn = 100000;
const int INF = 0x3f3f3f3f;
struct MaxFlow_Dinic {
struct Edge {
int to, cap;
Edge *nxt, *bak;
};
Edge pool[Maxn * 40 + 5];
Edge *ecnt, *G[Maxn * 8 + 5];
inline void addedge(int u, int v, int cap) {
Edge *p = ++ecnt;
p->to = v, p->cap = cap;
p->nxt = G[u], G[u] = p;
p->bak = p + 1;
p = ++ecnt;
p->to = u, p->cap = 0;
p->nxt = G[v], G[v] = p;
p->bak = p - 1;
}
int node, s, t;
int d[Maxn * 8 + 5];
Edge *cpy[Maxn * 8 + 5];
void init(int n) {
ecnt = &pool[0];
node = n;
for(int i = 1; i <= n; i++)
G[i] = NULL;
}
int dfs(int u, int tot) {
if(u == t) return tot;
int sum = 0;
for(;cpy[u] != NULL; cpy[u] = cpy[u]->nxt) {
int v = cpy[u]->to;
if(d[v] == d[u] + 1 && cpy[u]->cap > 0) {
int delta = dfs(v, min(tot - sum, cpy[u]->cap));
cpy[u]->cap -= delta, cpy[u]->bak->cap += delta;
sum += delta;
if(sum == tot) break;
}
}
return sum;
}
bool bfs(int _s, int _t) {
for(int i = 0 ; i <= node; i++)
d[i] = -1, cpy[i] = G[i];
queue<int> q;
q.push(_s), d[_s] = 1;
while(!q.empty()) {
int u = q.front();
q.pop();
for(Edge *p = G[u]; p != NULL; p = p->nxt) {
int v = p->to;
if(d[v] == -1 && p->cap > 0) {
d[v] = d[u] + 1;
if(v == _t) return true;
q.push(v);
}
}
}
return d[_t] != -1;
}
int dinic(int _s, int _t) {
int ret = 0;
s = _s, t = _t;
while(bfs(s, t)) ret += dfs(s, INF);
return ret;
}
};
MaxFlow_Dinic f;
int N, A[Maxn + 5], B[Maxn + 5];
int vis[Maxn + 5];
int main() {
#ifdef LOACL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d", &N);
f.init(N);
int cnt = 2 * N;
for(int i = 1; i <= N; i++)
scanf("%d", &A[i]), A[i]++;
for(int i = 1; i <= N; i++)
if(vis[i] == false) {
int p = i;
cnt++;
do {
vis[p] = true;
p = A[p];
f.addedge(cnt, p, INF), f.addedge(p, cnt, INF);
} while(p != i);
}
for(int i = 1; i <= N; i++)
scanf("%d", &B[i]), B[i]++, vis[i] = false;
for(int i = 1; i <= N; i++)
if(vis[i] == false) {
int p = i;
cnt++;
do {
vis[p] = true;
p = B[p];
f.addedge(cnt, p + N, INF), f.addedge(p + N, cnt, INF);
} while(p != i);
}
int s = cnt + 1, t = cnt + 2;
int ans = N;
f.node = cnt + 2;
for(int i = 1; i <= N; i++) {
if(i == A[i] && i == B[i] && A[i] == B[i])
ans--;
if(i == A[i] && i != B[i] && A[i] != B[i])
f.addedge(s, i + N, 1);
if(i != A[i] && i == B[i] && A[i] != B[i])
f.addedge(i, t, 1);
if(i != A[i] && i != B[i] && A[i] == B[i])
f.addedge(i, i + N, 1), f.addedge(i + N, i, 1);
if(i != A[i] && i != B[i] && A[i] != B[i])
f.addedge(i, i + N, 1);
}
printf("%d\n", ans - f.dinic(s, t));
return 0;
}