T1:子集和(七)
考虑折半搜索
先暴力预处理出左右两部分的子集和序列 \(b\) 和 \(c\)
并对两序列做排序
然后固定 \(c_i\),二分找到 \(b\) 序列中第一个大于 \(-c_i\) 的位置 \(j\),那么对答案的贡献就是 \(|b|-j+1\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
cin >> n;
vector<int> a(n);
rep(i, n) cin >> a[i];
int m = n/2;
int m2 = 1<<m;
vector<ll> b(m2);
rep(i, m2) {
ll s = 0;
rep(j, m) if (i>>j&1) s += a[j];
b[i] = s;
}
sort(b.begin(), b.end());
int k = n-m;
vector<int> x;
for (int i = m; i < n; ++i) x.push_back(a[i]);
int k2 = 1<<k;
vector<ll> c(k2);
rep(i, k2) {
ll s = 0;
rep(j, k) if (i>>j&1) s += x[j];
c[i] = s;
}
sort(c.begin(), c.end());
ll ans = 0;
for (int i = 0; i < k2; ++i) {
int j = upper_bound(b.begin(), b.end(), -c[i])-b.begin();
ans += m2-j;
}
cout << ans << '\n';
return 0;
}
T2:方格路径(二)
01bfs
原题:LC2290
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
const int di[] = {-1, 0, 1, 0};
const int dj[] = {0, 1, 0, -1};
int main() {
int n, m;
cin >> n >> m;
vector<string> s(n);
rep(i, n) cin >> s[i];
const int INF = 1001001001;
vector dist(n, vector<int>(m, INF));
deque<P> q;
dist[0][0] = 0;
q.emplace_back(0, 0);
while (q.size()) {
auto [i, j] = q.front(); q.pop_front();
int d = dist[i][j];
rep(v, 4) {
int ni = i+di[v], nj = j+dj[v];
if (ni < 0 or ni >= n or nj < 0 or nj >= m) continue;
if (dist[ni][nj] != INF) continue;
dist[ni][nj] = d+(s[i][j] == '*');
if (s[ni][nj] == '*') q.emplace_back(ni, nj);
else q.emplace_front(ni, nj);
}
}
int ans = dist[n-1][m-1]+(s[n-1][m-1] == '*');
cout << ans << '\n';
return 0;
}
T3:工程建设
拓扑排序
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n, m;
cin >> n >> m;
vector<int> t(n);
rep(i, n) cin >> t[i];
vector<vector<int>> to(n);
vector<int> deg(n);
rep(i, m) {
int a, b;
cin >> a >> b;
--a; --b;
to[a].push_back(b);
deg[b]++;
}
vector<ll> c(n);
queue<int> q;
rep(v, n) if (!deg[v]) q.push(v), c[v] = t[v];
while (q.size()) {
int v = q.front(); q.pop();
for (int u : to[v]) {
c[u] = max(c[u], c[v]);
--deg[u];
if (!deg[u]) {
c[u] += t[u];
q.push(u);
}
}
}
ll ans = 0;
rep(i, n) ans = max(ans, c[i]);
cout << ans << '\n';
return 0;
}
T4:组合数的余数
组合数的定义
\( \binom{n}{m} = \frac{n \times (n-1) \times \cdots \cdots \times (n-m+1)}{m!} \)
代码实现
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
//const int mod = 998244353;
const int mod = 1000000007;
struct mint {
ll x;
mint(ll x=0):x((x%mod+mod)%mod) {}
mint operator-() const {
return mint(-x);
}
mint& operator+=(const mint a) {
if ((x += a.x) >= mod) x -= mod;
return *this;
}
mint& operator-=(const mint a) {
if ((x += mod-a.x) >= mod) x -= mod;
return *this;
}
mint& operator*=(const mint a) {
(x *= a.x) %= mod;
return *this;
}
mint operator+(const mint a) const {
return mint(*this) += a;
}
mint operator-(const mint a) const {
return mint(*this) -= a;
}
mint operator*(const mint a) const {
return mint(*this) *= a;
}
mint pow(ll t) const {
if (!t) return 1;
mint a = pow(t>>1);
a *= a;
if (t&1) a *= *this;
return a;
}
// for prime mod
mint inv() const {
return pow(mod-2);
}
mint& operator/=(const mint a) {
return *this *= a.inv();
}
mint operator/(const mint a) const {
return mint(*this) /= a;
}
};
istream& operator>>(istream& is, mint& a) {
return is >> a.x;
}
ostream& operator<<(ostream& os, const mint& a) {
return os << a.x;
}
int main() {
int n, m;
cin >> n >> m;
mint ans = 1;
for (int i = 0; i < m; ++i) ans *= n-i;
for (int i = 1; i <= m; ++i) ans /= i;
cout << ans << '\n';
return 0;
}