A 社团招新
题面
思路
签到题,输入n后输出n即可,因为要成立最多的社团只能每个社团中仅有1人,
这样每两个社团之间的共同成员就是0个,是符合题意的最优解。
B 字符串
题面:
思路
用栈模拟,计算总次数判断奇偶性即可。
代码
struct Solver {
void solve() {
string s;
cin >> s;
n = s.size();
cnt = 0;
vector <char> ve;
for (char ch : s) {
if (ve.size() && ve.back() == ch) {
ve.pop_back();
cnt++;
} else ve.push_back(ch);
}
if (cnt & 1) {
cout << "Yes\n";
} else cout << "No\n";
}
};
D 香蕉
题面
思路
易知按照1,2,3...n的等差数列分配香蕉是使得答案为1的最小花费方案,
依此类推可知答案的花费具有单调性,因此可以二分。
代码
struct Solver {
void solve() {
ll n, m, a, b;
cin >> n >> m;
ll l = 1, r = m;
ans = 0;
while (l <= r) {
ll mid = l+r >>1;
if ([&](ll x){
a = m / x, b = m - a * x;
return (a+1)*a/2*x+(a+1)*b <= n;
}(mid)) {
ans = mid;
r = mid-1;
} else {
l = mid+1;
}
}
cout << ans << '\n';
}
};
F 摘橘子
题面
思路
用dp[i][j] 表示前i棵树上总共摘的橘子数量%m等于j的方案数,n*m*m三层循环dp即可。
代码
struct Solver {
void solve() {
cin >> n >> m;
vector <int> ve (n);
vector <vector <ll> > dp (n, vector <ll> (m));
for (int i = 0; i < n; ++i) {
cin >> ve[i];
}
for (int i = 0; i < m; ++i) {
dp[0][i] = ve[0] / m + (i<=ve[0] % m);
}
for (int i = 1; i < n; ++i) {
for (int j = 0; j < m; ++j) {
for (int l = 0; l < m; ++l) {
dp[i][(j+l)%m] += dp[i-1][j] * (ve[i] / m + (l <= ve[i] % m)) % mod;
dp[i][(j+l)%m] %= mod;
}
}
}
cout << dp[n-1][0] << '\n';
}
};
G 排列
题面
思路
当N > M时必然有解,当N<=M时,N和M都较小,直接使用匈牙利算法进行匹配即可。
代码
//pf[i] = i*i
struct Solver {
void solve() {
cin >> n >> m;
ans = 0;
if (n > m) {
cout << "Yes\n";
return;
}
vector <int> p (n+m+5);
vector <bool> vis (n+m+5);
function<bool(int)> match = [&] (int i) {
for (int j = 0; j < pf.size(); ++j) {
int num = pf[j]+i;
if (num > m && num <= m+n && !vis[num]) {
vis[num] = 1;
if (p[num] == 0 || match(p[num])) {
p[num] = i;
return true;
}
}
num = pf[j]-i;
if (num > m && num <= m+n && !vis[num]) {
vis[num] = 1;
if (p[num] == 0 || match(p[num])) {
p[num] = i;
return true;
}
}
}
return false;
};
for (int i = 1; i <= n; ++i) {
vis = vector <bool> (n+m+5);
if (!match(i)) {
cout << "No\n";
return;
}
}
cout << "Yes\n";
}
};
J 在一起
题面
思路
题中给出了一棵树,每条边的权值与每点的权值,容易想到树形DP,
依题意推出转移方程后做两次DFS即可,转移方程见代码。
代码
struct Solver {
void solve() {
cin >> n;
ans = INF;
vector <ll> pcnt (n), preVal(n), preCnt(n);
vector <vector <pair<int, ll> > > ve (n);
for (int i = 0; i < n; ++i) {
cin >> pcnt[i];
}
for (int i = 1; i < n; ++i) {
cin >> a >> b >> c;
--a, --b;
ve[a].emplace_back(b, c);
ve[b].emplace_back(a, c);
}
function<void (int, int) > dfs0 = [&](int now, int fa) {
for (auto p: ve[now]) {
if (p.first != fa) {
dfs0(p.first, now);
preVal[now] += preVal[p.first] + preCnt[p.first] * p.second;
preCnt[now] += preCnt[p.first];
}
}
preCnt[now] += pcnt[now];
};
function<void (int, int) > dfs1 = [&](int now, int fa) {
for (auto p: ve[now]) {
if (p.first != fa) {
preVal[p.first] = preVal[now]
+ preCnt[now]*p.second
- 2*preCnt[p.first]*p.second;
preCnt[p.first] = preCnt[now];
dfs1(p.first, now);
}
}
};
dfs0(0, 0);
dfs1(0, 0);
ans = std::min_element(preVal.begin(), preVal.end()) - preVal.begin() + 1;
cout << ans << ' ' << preVal[ans-1] << '\n';
}
};