Problem Setter: hank55663
補圖上數
原圖上三個點如果有
答案就是
https://github.com/OmeletWithoutEgg/ckiseki/blob/master/codes/Graph/CountCycles.cpp
TC:
Problem Setter: hank55663
數
https://github.com/OmeletWithoutEgg/ckiseki/blob/master/codes/Graph/CountCycles.cpp
TC:
Problem Setter: hank55663
數
注意
我的做法是枚舉三條相鄰邊
TC:
void solve() {
int N, M; cin >> N >> M;
vector<pii> edges(M);
vector<bitset<maxn>> adj_mat(N+1);
for (auto &[u, v] : edges) {
cin >> u >> v;
adj_mat[u][v] = adj_mat[v][u] = 1;
}
vector cap(N+1, vector<int>(N+1, 0));
for (int i = 1; i <= N; ++i) for (int j = 1; j <= N; ++j) cap[i][j] = (adj_mat[i] & adj_mat[j]).count();
ll ans = 0;
for (int i = 0; i < M; ++i) for (int j = 0; j < M; ++j) for (int k = 0; k < M; ++k) {
if (i == j or i == k or j == k) continue;
auto [i1, i2] = edges[i];
auto [j1, j2] = edges[j];
auto [k1, k2] = edges[k];
if (i1 == j1) swap(i1, i2);
if (i2 == j2) swap(j1, j2);
if (i1 == j2) swap(i1, i2), swap(j1, j2);
if (j1 == k1) swap(j1, j2);
if (j2 == k2) swap(k1, k2);
if (i2 == j1 and j2 == k1 and i1 != k2) {
ans += cap[i1][k2] - adj_mat[i2][k2] - adj_mat[i1][k1];
}
}
cout << ans << "\n";
}
Problem Setter: henotrix
經典 greedy 題,每個 column 由小排到大就是最佳解。
證明可以用 exchange argument 證。
void solve() {
int N, M; cin >> N >> M;
vector arr(M, vector<int>(N, 0));
for (int i = 0; i < N; ++i) {
for (int j = 0; j < M; ++j) cin >> arr[j][i];
}
for (int j = 0; j < M; ++j) sort(ALL(arr[j]));
int ans = 0;
for (int i = 0; i < N; ++i) {
for (int j = 0; j+1 < M; ++j) {
ans += abs(arr[j][i] - arr[j+1][i]);
}
}
cout << ans << "\n";
}
Problem Setter: henotrix
觀察一下應該就能發現只要不是
void solve() {
int N, A, B, X; cin >> N >> A >> B >> X;
if (A == N-1 and X != 1) cout << "No" << "\n";
else if (B == N-1 and X != N) cout << "No" << "\n";
else cout << "Yes" << "\n";
}
Problem Setter: henotrix
經典 greedy,把 gun 依照左界排序。
void solve() {
int n, m;
cin >> n >> m;
vector<int> X(n);
for (auto &x: X) cin >> x;
vector<pair<int,int>> G(m);
for (auto &[l,r]: G) cin >> l >> r;
sort(ALL(X));
sort(ALL(G), [&](auto a, auto b) {
return a.first < b.first;
});
bool can = true;
int ans = 0;
for (int i = 0, j = 0; i < n; ) {
int mx = -1;
while (j < m and G[j].first <= X[i]) {
mx = max(mx, G[j].second);
j++;
}
if (mx < X[i]) {
can = false;
break;
}
ans++;
while (i < n and X[i] <= mx)
i++;
}
if (not can) ans = -1;
cout << ans << endl;
}
Problem Setter: henotrix
看限制可以大概感覺的出來要把邊由小到大加進去離線回答詢問。
只要一個 DSU 來維護最大連通塊大小就好了。
struct Qry {
int id, k, ans;
};
struct Edge {
int u, v, w;
};
struct DSU {
vector<int> ary;
int mx = 1;
DSU(int n): ary(n, -1) {}
int find(int x) { return ary[x] < 0 ? x : ary[x] = find(ary[x]); }
bool merge(int u, int v) {
debug(u, v);
u = find(u), v = find(v);
if (u == v) return false;
if (-ary[u] < -ary[v]) swap(u, v);
ary[u] += ary[v];
mx = max(mx, -ary[u]);
debug(mx);
ary[v] = u;
return true;
}
int mxsz() {
return mx;
}
};
signed main() {
fast;
int n, m, Q;
cin >> n >> m >> Q;
vector<Edge> edges(m);
for (auto &[u,v,w]: edges) {
cin >> u >> v >> w;
u--; v--;
}
vector<Qry> qry(Q);
for (int q = 0; q < Q; q++) {
qry[q].id = q;
cin >> qry[q].k;
}
sort(ALL(qry), [&](auto& x, auto& y) {
return x.k < y.k;
});
sort(ALL(edges), [&](auto& x, auto& y) {
return x.w < y.w;
});
DSU dsu(n);
for (int q = 0, e = 0; q < Q; q++) {
while (e < m and edges[e].w <= qry[q].k) {
dsu.merge(edges[e].u, edges[e].v);
e++;
}
debug(qry[q].id, dsu.mxsz());
qry[q].ans = dsu.mxsz();
}
sort(ALL(qry), [&](auto& x, auto& y) {
return x.id < y.id;
});
for (auto q: qry)
cout << q.ans << '\n';
return 0;
}
Problem Setter: henotrix
找
最短距離要嘛是戳在一條邊上,要嘛是戳在一個點上。
範圍很小,
Problem Setter: henotrix
經典最小割題。
/// 此處省略 Dinic 模板
signed main() {
int n, ans = 0;
cin >> n;
vector<int> arr(n+2), dp(n+2), weight(n+2);
for(int i=1;i<=n;i++)
cin >> arr[i];
arr[0] = 0, arr[n+1] = n+1;
for(int i=1;i<=n;i++)
cin >> weight[i], ans += weight[i];
weight[0] = weight[n+1] = 2e9;
arr[n+1] = n+1;
for(int i=1;i<=n+1;i++)
for(int j=0;j<i;j++)
if(arr[j] < arr[i])
dp[i] = max(dp[i], dp[j]+1);
Dinic dinic;
dinic.init(2*(n+2));
for(int i=0;i<=n+1;i++)
dinic.add_edge(2*i, 2*i+1, weight[i]);
for(int i=0;i<=n+1;i++)
for(int j=0;j<i;j++)
if(dp[i] == dp[j]+1 and arr[j] < arr[i])
dinic.add_edge(2*j+1, 2*i, 2e9);
auto rrr = ans-dinic.max_flow(0, (n+1)*2+1);
cout << rrr <<'\n';
return 0;
}
Problem Setter: henotrix
把式子推一推就會發現你要處理每個位移的匹配位置數量,這是經典卷積題。
對每個字元分開做,把
https://tioj.ck.tp.edu.tw/problems/1035
/// 此處省略 NTT 模板(快速數論變換)
/// fpow(base, exp = MOD-2) 是快速冪 base^exp mod MOD
void solve() {
string S, T; cin >> S >> T;
int K; cin >> K;
int N = ssize(S), M = ssize(T);
int N_pow2 = (2 << __lg(N+1));
vector<int> match(N-M+1, 0);
for (char c = 'a'; c <= 'h'; ++c) {
vector<int> a(N_pow2, 0), b(N_pow2, 0);
for (int i = 0; i < N; ++i) a[i] = (S[i] == c);
for (int i = 0; i < M; ++i) b[i] = (T[M-i-1] == c);
NTT ntt;
ntt(a, N_pow2, false);
ntt(b, N_pow2, false);
for (int i = 0; i < N_pow2; ++i) a[i] = (a[i] * b[i]) % MOD;
ntt(a, N_pow2, true);
for (int j = M-1; j <= N-1; ++j) match[j-(M-1)] += a[j];
}
int ans = 1;
for (int i = 0; i <= N-M; ++i) {
if (match[i] == M) continue;
ans = ans * (1 - fpow(match[i], K) * fpow(fpow(M, K)) % MOD + MOD) % MOD;
}
cout << ans << "\n";
}
Problem Setter: truckski
要算
先嘗試將答案表示為
定義
可得
注意到
要計算
Problem Setter: truckski
不能取相鄰數字的最大和,經典 DP。
用
void solve() {
ll N; cin >> N;
vector<ll> v(N);
for (ll &x : v) cin >> x, x = max<ll>(x, 0);
vector<ll> dp = v;
for (int i = 1; i < N; ++i) {
dp[i] = max(dp[i-1], (i >= 2 ? dp[i-2] : 0) + v[i]);
}
cout << *max_element(ALL(dp)) << "\n";
}
Problem Setter: truckski
int H = 0;
for (int i = 1; i <= n; ++i) {
if (c[i] >= i) ++H;
}