agc001

你说得太对辣發表於2024-06-29

A.

幽默題,不說了

B.

結論題, ans=3(n-gcd(n,x))

c.

分類討論 k 的奇偶性。若 k 為偶數,則列舉直徑上的點,向兩邊dfs在 \frac{k}{2} 步之內能到的點。若 k 為奇數,列舉直徑上的一條邊即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 2005;
const int inf = 1e18;
int head[N], ecnt;
struct edge {
int next, to;
}e[N << 2];
void addedge(int u, int v) {
e[++ ecnt].to = v;
e[ecnt].next = head[u];
head[u] = ecnt;
}
int n, k;
int cnt;
int vis[N];
void dfs(int u, int fa, int p) {
if(vis[u]) return;
vis[u] = 1;
cnt ++;
if(p == 0) return;
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(v == fa) continue;
dfs(v, u, p - 1);
}
}
void solve1() {
int ans = inf;
for(int i = 1; i <= n; i ++) {
cnt = 0;
for(int j = 0; j <= n; j ++) vis[j] = 0;
dfs(i, 0, k / 2);
ans = min(ans, n - cnt);
}
cout << ans << endl;
}
struct node {
int x, y;
};
vector<node> g;
void solve2() {
int ans = inf;
for(int i = 0; i < g.size(); i ++) {
int x = g[i].x, y = g[i].y;
cnt = 0;
for(int j = 0; j <= n; j ++) vis[j] = 0;
dfs(x, y, k / 2);
dfs(y, x, k / 2);
ans = min(ans, n - cnt);
}
cout << ans << endl;
}
signed main() {
memset(head, -1, sizeof head);

cin >> n >> k;
for(int i = 1; i < n; i ++) {
int u, v;
cin >> u >> v;
addedge(u, v);
addedge(v, u);
g.push_back({u, v});
}
if(k % 2 == 0) solve1();
else solve2();
}

d.

牛逼人類智慧構造!根本想不到,貼個題解。https://www.luogu.com.cn/article/kdvcj5eo

e.

考慮 \binom{x+y}{x} 的組合意義為從 (0,0) 走到 (x,y) 的方案數,所以題目轉換為了從 (0,0) 走到 (a_i+a_j,b_i+b_j) 的方案數。

這個求起來還是 O(n^2) 的。將所有點平移一下,變成求 (-a_i,-b_i)(a_j, b_j) 的方案數。這個怎麼dp呢?讓所有的 (-a_i, -b_i) 為起點,求到所有 (a_j, b_j) 的方案數。然後 dp[i][j] = dp[i-1][j]+dp[i][j-1]。發現這個會算重,會算上 (-a_i,-b_i)(a_i,b_i) 的方案數,所以每次減去 \binom{a[i]*2+b[i]*2}{b[i]*2} 即可,最後除以2。

不過為什麼最後答案直接除以二會wa很多,乘2的逆元就a了,好奇怪的。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e6 + 7;
const int mod = 1e9 + 7;
int a[N], b[N];
const int M = 2200;
int dp[4500][4500];
int fac[N], infac[N];
int qpow(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res % mod;
}
int getc(int a, int b) {
return fac[a] % mod * infac[b] % mod * infac[a - b] % mod;
}
signed main() {
fac[0] = infac[0] = 1;
for(int i = 1; i <= N / 2; i ++) {
fac[i] = fac[i - 1] * i % mod;
infac[i] = qpow(fac[i], mod - 2);
}
int ans = 0;
int n;
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i] >> b[i];
for(int i = 1; i <= n; i ++) {
dp[M - a[i]][M - b[i]] ++;
}
for(int i = 1; i <= M * 2; i ++) {
for(int j = 1; j <= M * 2; j ++) {
dp[i][j] = (dp[i][j] + (dp[i - 1][j] + dp[i][j - 1]) % mod) % mod;
}
}
for(int i = 1; i <= n; i ++) {
ans = (ans + dp[M + a[i]][M + b[i]]) % mod;
ans = (ans - getc(2 * a[i] + 2 * b[i], a[i] * 2) % mod + mod) % mod;
}
ans %= mod;
cout << (ans * qpow(2, mod - 2)) % mod << endl;
return 0;
}

AGC002

a.

簡單題

b.

簡單題,稍微注意一下要記錄每個盒子裡的球的個數,若從一個球個數為1的盒子裡拿走球,那這個盒子一定不可能有紅球。

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 7;
int x[N];
int s[N];
int main() {
int n, m;
cin >> n >> m;
x[1] = 1;
for(int i = 1; i <= n; i ++) s[i] = 1;
for(int i = 1; i <= m; i ++) {
int a, b;
cin >> a >> b;
if(x[a]) {
x[b] = 1;
if(s[a] == 1) {
x[a] = 0;
}
}
s[a] -- ;
s[b] ++;
}
int cnt = 0;
for(int i = 1; i <= n; i ++) if(x[i] && s[i]) cnt ++;
cout << cnt << endl;
}

c.