考虑两个人不互相影响的情况,显然只需要判断是否存在两个相邻的障碍即可;
当原来在前面的人要走到后面时,需要存在三个连续的空位来跳过去。
#include
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, a, b, c, d;
string s;
cin >> n >> a >> b >> c >> d >> s;
--a;
--b;
--c;
--d;
auto check = [&](int a, int b) {
for (int i = a; i < b; ++i) {
if (s[i] == '#' && s[i + 1] == '#') {
return false;
}
}
return true;
};
if (!check(a, c) || !check(b, d)) {
cout << "No" << "\n";
} else if (c <= d) {
cout << "Yes" << "\n";
} else {
for (int i = b; i <= d; ++i) {
if (i - 1 >= 0 && i + 1 < n && s[i] == '.' && s[i - 1] == '.' && s[i + 1] == '.') {
cout << "Yes" << "\n";
return 0;
}
}
cout << "No" << "\n";
}
return 0;
}
可以将一次操作看成将 A A A 往后移,不难发现能移就移是最优的,那么倒着扫一遍维护后面 B C BC BC 的个数即可。
#include
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
string s;
cin >> s;
reverse(s.begin(), s.end());
long long ans = 0;
int stage = 0;
int back = 0;
for (auto c : s) {
if (c == 'A') {
if (stage) {
stage = back = 0;
} else {
ans += back;
}
} else if (c == 'B') {
if (stage) {
stage = 0;
back++;
} else {
stage = back = 0;
}
} else {
if (stage) {
back = 0;
} else {
stage = 1;
}
}
}
cout << ans << "\n";
return 0;
}
显然劣势的考试会选择 l l l ,优势的会选择 u u u 。由于贡献的导数是不降的,所以一定是选若干个喂满,至多有一个不喂;二分答案后判断即可。
#include
using namespace std;
struct point {
int b, l, u;
long long s;
bool operator < (const point &other) const {
return s > other.s;
}
};
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
vector<point> a(n);
long long need = 0;
for (int i = 0; i < n; ++i) {
cin >> a[i].b >> a[i].l >> a[i].u;
need += (long long) a[i].b * a[i].l;
a[i].s = (long long) a[i].l * a[i].b + (long long) a[i].u * (m - a[i].b);
}
sort(a.begin(), a.end());
auto check = [&](long long t) {
int full = t / m, small = t % m;
long long sum = 0;
for (int i = 0; i <= full; ++i) {
sum += a[i].s;
}
long long ans = 0;
for (int i = 0; i < n; ++i) {
long long single = a[i].b <= small ? (long long) a[i].u * small - (long long) (a[i].u - a[i].l) * a[i].b : (long long) a[i].l * small;
if (i <= full) {
ans = max(ans, sum - a[i].s + single);
} else {
ans = max(ans, sum - a[full].s + single);
}
}
return ans >= need;
};
long long l = 0, r = (long long) n * m;
while (l < r) {
long long mid = (l + r) >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
cout << r << "\n";
return 0;
}
用 4 4 4 个点表示四种符号,优化费用流建图即可。
#include
using namespace std;
using cap_t = int;
using cost_t = long long;
const cap_t cap_inf = 1 << 30;
const cost_t cost_inf = 1ll << 60;
namespace flow {
struct edge {
int to, rev;
cost_t cost;
cap_t cap;
edge(int t, cap_t c, cost_t w, int r) {
to = t;
rev = r;
cap = c;
cost = w;
}
};
vector<vector<edge>> adj;
vector<cost_t> dist;
int n, source, sink;
vector<bool> visit;
vector<int> cur;
cost_t res;
cap_t ans;
void init(int v, int s, int t) {
n = v;
ans = res = 0;
source = s;
sink = t;
adj.clear();
adj.resize(n);
cur.resize(n);
dist.resize(n);
visit.resize(n);
}
void add(int x, int y, cap_t c, cost_t w) {
adj[x].emplace_back(y, c, w, adj[y].size());
adj[y].emplace_back(x, 0, -w, adj[x].size() - 1);
}
bool spfa() {
queue<int> q;
for (int i = 0; i < n; ++i) {
dist[i] = cost_inf;
visit[i] = false;
cur[i] = 0;
}
dist[source] = 0;
q.push(source);
while (!q.empty()) {
int x = q.front();
q.pop();
visit[x] = false;
for (auto e : adj[x]) {
if (e.cap && dist[e.to] > dist[x] + e.cost) {
dist[e.to] = dist[x] + e.cost;
if (!visit[e.to]) {
visit[e.to] = true;
q.push(e.to);
}
}
}
}
return dist[sink] != cost_inf;
}
cap_t dfs(int x, cap_t f) {
if (x == sink) {
return f;
}
visit[x] = true;
cap_t res = 0;
for (int &i = cur[x]; i < (int) adj[x].size(); ++i) {
edge &e = adj[x][i];
if (e.cap && dist[e.to] == dist[x] + e.cost && !visit[e.to]) {
cap_t w = dfs(e.to, min(e.cap, f - res));
res += w;
e.cap -= w;
adj[e.to][e.rev].cap += w;
if (res == f) {
visit[x] = false;
return res;
}
}
}
dist[x] = cost_inf;
return res;
}
pair<cap_t, cost_t> min_cost_max_flow() {
while (spfa()) {
cap_t flow = dfs(source, cap_inf);
ans += flow;
res += flow * dist[sink];
}
return make_pair(ans, res);
}
}
using flow::source;
using flow::sink;
using flow::init;
using flow::add;
using flow::min_cost_max_flow;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
init(n * 2 + 6, n * 2, n * 2 + 1);
for (int i = 0; i < n; ++i) {
int x, y, z;
cin >> x >> y >> z;
add(source, i, z, 0);
add(i, n * 2 + 2, z, x + y);
add(i, n * 2 + 3, z, x - y);
add(i, n * 2 + 4, z, y - x);
add(i, n * 2 + 5, z, -(x + y));
}
for (int i = 0; i < n; ++i) {
int x, y, z;
cin >> x >> y >> z;
add(i + n, sink, z, 0);
add(n * 2 + 2, i + n, z, -(x + y));
add(n * 2 + 3, i + n, z, y - x);
add(n * 2 + 4, i + n, z, x - y);
add(n * 2 + 5, i + n, z, x + y);
}
cout << -min_cost_max_flow().second << "\n";
return 0;
}
枚举最后停留在哪个点,然后点只会往上移,用类似求重心的方法做个DP即可。
#include
using namespace std;
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
string s;
cin >> n >> s;
vector<vector<int>> adj(n);
for (int i = 0; i < n - 1; ++i) {
int from, to;
cin >> from >> to;
--from;
--to;
adj[from].push_back(to);
adj[to].push_back(from);
}
int ans = 1 << 30;
for (int i = 0; i < n; ++i) {
vector<int> size(n);
vector<int> foo(n);
vector<int> bar(n);
function<void(int, int)> dfs = [&](int x, int p) {
size[x] = s[x] == '1';
vector<int> son;
for (auto y : adj[x]) {
if (y != p) {
son.push_back(y);
dfs(y, x);
size[x] += size[y];
foo[x] += foo[y];
}
}
if (!son.empty()) {
sort(son.begin(), son.end(), [&](int u, int v) {
return foo[u] < foo[v];
});
int other = 0;
for (int i = 0; i < (int) son.size() - 1; ++i) {
other += foo[son[i]];
}
bar[x] = max(0, bar[son.back()] - other);
}
foo[x] += size[x];
bar[x] += size[x];
};
dfs(i, -1);
if (bar[i] == size[i] && (foo[i] - size[i]) % 2 == 0) {
ans = min(ans, (foo[i] - size[i]) / 2);
}
}
if (ans == 1 << 30) {
cout << -1 << "\n";
} else {
cout << ans << "\n";
}
return 0;
}
首先将概率数组 p p p 进行 FWT。
考虑如何求 t t t 次操作后为 u u u 的概率,由 iFWT 的定义可知概率为 ∑ i ( − 1 ) p o p c o u n t ( i & u ) p i t \sum_i (-1)^{popcount(i\& u)} p_i^t ∑i(−1)popcount(i&u)pit ,写成母函数的形式,有 f [ u ] ( x ) = ∑ i ( − 1 ) p o p c o u n t ( i & u ) 1 1 − p i x f[u](x) = \sum_{i} (-1)^{popcount(i\&u)} \frac{1}{1-p_ix} f[u](x)=∑i(−1)popcount(i&u)1−pix1 ,而不难发现第一次到的概率就是 g [ u ] ( x ) = f [ u ] ( x ) / f [ 0 ] ( x ) g[u](x) =f[u](x) / f[0](x) g[u](x)=f[u](x)/f[0](x) ,我们要求的是 g [ u ] ′ ( 1 ) g[u]'(1) g[u]′(1) 的值,用 ( f / g ) ′ = ( f ′ g − g ′ f ) / g 2 (f/g)' = (f'g-g'f)/g^2 (f/g)′=(f′g−g′f)/g2 计算即可。
注意这里会出现除 0 0 0 的情况,所以分子分母需要同时乘上 1 − x 1-x 1−x 进行计算。
#include
using namespace std;
const int md = 998244353;
inline void add(int &x, int y) {
x += y;
if (x >= md) {
x -= md;
}
}
inline void sub(int &x, int y) {
x -= y;
if (x < 0) {
x += md;
}
}
inline int mul(int x, int y) {
return (int) ((long long) x * y % md);
}
inline int inv(int a) {
if (a < 0) {
a += md;
}
int b = md, u = 0, v = 1;
while (a) {
int t = b / a;
b -= t * a;
swap(a, b);
u -= t * v;
swap(u, v);
}
if (u < 0) {
u += md;
}
return u;
}
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
vector<int> a(1 << n);
int sum = 0;
for (int i = 0; i < 1 << n; ++i) {
cin >> a[i];
sum += a[i];
}
sum = inv(sum);
for (int i = 0; i < 1 << n; ++i) {
a[i] = mul(a[i], sum);
}
for (int i = 1; i < 1 << n; i <<= 1) {
for (int j = 0; j < 1 << n; j += i << 1) {
for (int k = 0; k < i; ++k) {
int u = a[j + k], v = a[j + k + i];
a[j + k] = (u + v) % md;
a[j + k + i] = (u - v + md) % md;
}
}
}
a[0] = 0;
for (int i = 1; i < 1 << n; ++i) {
a[i] = inv(a[i] - 1);
}
for (int i = 1; i < 1 << n; i <<= 1) {
for (int j = 0; j < 1 << n; j += i << 1) {
for (int k = 0; k < i; ++k) {
int u = a[j + k], v = a[j + k + i];
a[j + k] = (u + v) % md;
a[j + k + i] = (u - v + md) % md;
}
}
}
cout << 0 << "\n";
for (int i = 1; i < 1 << n; ++i) {
sub(a[i], a[0]);
cout << a[i] << "\n";
}
return 0;
}