UOJ Round #12
A
结论:答案是 YES
当且仅当对于任意一个数,\(A\) 中比它小且在它前面的数在 \(B\) 中也在它前面。
证明:必要性显然,充分性考虑直接把 \(A\) 中的数从前往后挪到 \(B\) 中对应的位置,则挪不动时一定与结论矛盾。
那么直接三维数点即可,也可以改变枚举顺序后变成二维数点。
#include <bits/stdc++.h>
#define IL __inline__ __attribute__((always_inline))
#define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
#define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
#define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
#define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)
typedef long long LL;
template <class T>
IL bool chkmax(T &a, const T &b) {
return a < b ? ((a = b), 1) : 0;
}
template <class T>
IL bool chkmin(T &a, const T &b) {
return a > b ? ((a = b), 1) : 0;
}
template <class T>
IL T mymax(const T &a, const T &b) {
return a > b ? a : b;
}
template <class T>
IL T mymin(const T &a, const T &b) {
return a < b ? a : b;
}
template <class T>
IL T myabs(const T &a) {
return a > 0 ? a : -a;
}
const int INF = 0X3F3F3F3F;
const double EPS = 1E-8, PI = acos(-1.0);
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
#define SZ(x) ((int)(x).size())
const int MAXN = 100000 + 5;
struct BinaryIndexedTree {
int a[MAXN], n;
#define lowbit(x) ((x) & -(x))
void modify(int i, int x) {
for (; i <= n; i += lowbit(i)) {
a[i] += x;
}
}
int query(int i) {
int ret = 0;
for (; i; i -= lowbit(i)) {
ret += a[i];
}
return ret;
}
} bit;
int a[MAXN], b[MAXN], p[MAXN], q[MAXN], ans[MAXN];
void solve(int l, int r) {
if (l == r) {
return;
}
int mid = (l + r) >> 1, len = r - l + 1;
solve(l, mid);
static int tp[MAXN];
For(i, l, r) {
tp[i - l + 1] = i;
}
std::sort(tp + 1, tp + len + 1, [&](int a, int b) {
return p[a] < p[b];
});
For(i, 1, len) {
if (tp[i] <= mid) {
bit.modify(q[tp[i]], 1);
} else {
ans[tp[i]] += bit.query(q[tp[i]]);
}
}
For(i, l, mid) {
bit.modify(q[i], -1);
}
solve(mid + 1, r);
}
int main() {
int n;
scanf("%d", &n);
For(i, 1, n) {
scanf("%d", &a[i]);
p[a[i]] = i;
}
For(i, 1, n) {
scanf("%d", &b[i]);
q[b[i]] = i;
}
bit.n = n;
solve(1, n);
For(i, 1, n) {
if (bit.query(p[i]) > ans[i]) {
puts("NO");
exit(0);
}
bit.modify(p[i], 1);
}
puts("YES");
return 0;
}
B
原图一定是竞赛图,则缩点之后是一条链,答案的期望相当于所有连通块满足“所有与这个连通块相连的边都是从这个连通块连出“的概率之和。
发现同一个大小的连通块的答案可以一起算(只与特殊边有关),考虑状压 DP。
考虑只保留特殊边形成的连通块,则每个连通块至多有 \(m + 1\) 个点,枚举这些点中哪些点在连通块内,贡献可以直接计算,合并连通块做个背包即可。
#include <bits/stdc++.h>
#define IL __inline__ __attribute__((always_inline))
#define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
#define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
#define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
#define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)
typedef long long LL;
template <class T>
IL bool chkmax(T &a, const T &b) {
return a < b ? ((a = b), 1) : 0;
}
template <class T>
IL bool chkmin(T &a, const T &b) {
return a > b ? ((a = b), 1) : 0;
}
template <class T>
IL T mymax(const T &a, const T &b) {
return a > b ? a : b;
}
template <class T>
IL T mymin(const T &a, const T &b) {
return a < b ? a : b;
}
template <class T>
IL T myabs(const T &a) {
return a > 0 ? a : -a;
}
const int INF = 0X3F3F3F3F;
const double EPS = 1E-8, PI = acos(-1.0);
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
#define SZ(x) ((int)(x).size())
namespace Math {
const int MOD = 998244353;
IL int add(int a, int b) {
a += b;
return a >= MOD ? a - MOD : a;
}
template <class ...Args>
IL int add(int a, const Args &...args) {
a += add(args...);
return a >= MOD ? a - MOD : a;
}
IL int sub(int a, int b) {
a -= b;
return a < 0 ? a + MOD : a;
}
IL int mul(int a, int b) {
return (LL)a * b % MOD;
}
template <class ...Args>
IL int mul(int a, const Args &...args) {
return (LL)a * mul(args...) % MOD;
}
IL int quickPow(int a, int p) {
int ret = 1;
for (; p; p >>= 1, a = mul(a, a)) {
if (p & 1) {
ret = mul(ret, a);
}
}
return ret;
}
}
using namespace Math;
const int MAXN = 40 + 5, MAXM = 20 + 5, MASK = 1 << 20;
using Pair = std::pair<int, int>;
int f[MAXN], g[MAXN], to[MAXN], G[MAXN][MAXN], n, m, cnt;
Pair eg[MAXM];
bool vis[MAXN];
void DFS(int u) {
OK;
to[u] = cnt ++;
vis[u] = 1;
For(i, 1, n) {
if (~G[u][i] && !vis[i]) {
DFS(i);
}
}
}
int main() {
memset(G, -1, sizeof G);
scanf("%d%d", &n, &m);
int p = quickPow(10000, MOD - 2);
For(i, 1, m) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
eg[i] = {u, v};
G[u][v] = mul(w, p), G[v][u] = mul(10000 - w, p);
}
f[0] = 1;
int cur = 0;
For(i, 1, n) {
if (!vis[i]) {
memset(to, -1, sizeof to);
memset(g, 0, sizeof g);
cnt = 0;
DFS(i);
FOR(S, 0, 1 << cnt) {
int w = __builtin_popcount(S), c = 1;
For(j, 1, m) {
int x = eg[j].first, y = eg[j].second, a = to[x], b = to[y];
if (!~a || !~b) {
continue;
}
if (((S >> a) & 1) && ((~S >> b) & 1)) {
c = mul(c, add(G[x][y], G[x][y]));
} else if (((~S >> a) & 1) && ((S >> b) & 1)) {
c = mul(c, add(G[y][x], G[y][x]));
}
}
g[w] = add(g[w], c);
}
cur += cnt;
Rep(j, cur, 1) {
For(k, 1, mymin(j, cnt)) {
f[j] = add(f[j], mul(f[j - k], g[k]));
}
}
}
}
int ans = 0;
For(i, 1, n) {
ans = add(ans, mul(f[i], quickPow((MOD + 1) / 2, i * (n - i))));
}
printf("%d\n", mul(ans, quickPow(10000, n * (n - 1))));
return 0;
}
C
每一个时刻每个位置的值一定可以表示成 \(\frac{ax+b}{cx+d}\),即 \(p+\frac{q}{x+r}\) 的形式,其中除了 \(x\) 外都是常数。
那么稍微化一下就是多点求值了。
#include <bits/stdc++.h>
#define IL __inline__ __attribute__((always_inline))
#define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
#define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
#define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
#define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)
typedef long long LL;
template <class T>
IL bool chkmax(T &a, const T &b) {
return a < b ? ((a = b), 1) : 0;
}
template <class T>
IL bool chkmin(T &a, const T &b) {
return a > b ? ((a = b), 1) : 0;
}
template <class T>
IL T mymax(const T &a, const T &b) {
return a > b ? a : b;
}
template <class T>
IL T mymin(const T &a, const T &b) {
return a < b ? a : b;
}
template <class T>
IL T myabs(const T &a) {
return a > 0 ? a : -a;
}
const int INF = 0X3F3F3F3F;
const double EPS = 1E-10, PI = acos(-1.0);
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
#define SZ(x) ((x).size())
namespace Math {
const int MOD = 998244353;
IL int add(int a, int b) {
a += b;
return a >= MOD ? a - MOD : a;
}
template <class ...Args>
IL int add(int a, const Args &...args) {
a += add(args...);
return a >= MOD ? a - MOD : a;
}
IL int sub(int a, int b) {
a -= b;
return a < 0 ? a + MOD : a;
}
IL int mul(int a, int b) {
return (LL)a * b % MOD;
}
template <class ...Args>
IL int mul(int a, const Args &...args) {
return (LL)a * mul(args...) % MOD;
}
IL int quickPow(int a, int p) {
int ret = 1;
for (; p; p >>= 1, a = mul(a, a)) {
if (p & 1) {
ret = mul(ret, a);
}
}
return ret;
}
}
using namespace Math;
const int MAXN = 100000 + 5, LOG = 19, G = 3, G_inv = 332748118, INV_2 = 499122177;
namespace Poly {
int pos[1 << LOG], root[1 << LOG], root_inv[1 << LOG], len;
IL void init(int n) {
for (; 1 << len < n; ++ len);
FOR(i, 0, 1 << len) {
pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (len - 1));
}
int w = quickPow(G, (MOD - 1) >> len);
root[0] = 1;
FOR(i, 1, 1 << len) {
root[i] = mul(root[i - 1], w);
}
w = quickPow(G_inv, (MOD - 1) >> len);
root_inv[0] = 1;
FOR(i, 1, 1 << len) {
root_inv[i] = mul(root_inv[i - 1], w);
}
}
IL void NTT(int *a, int n, int *root) {
int shift = __builtin_ctz((1 << len) / n);
FOR(i, 0, n) {
if (i > pos[i] >> shift) {
std::swap(a[i], a[pos[i] >> shift]);
}
}
for (int i = 2; i <= n; i <<= 1) {
int k = i >> 1;
shift = __builtin_ctz((1 << len) / i);
for (int *p = a; p != a + n; p += i) {
FOR(j, 0, k) {
int temp = mul(p[j + k], root[j << shift]);
p[j + k] = sub(p[j], temp);
p[j] = add(p[j], temp);
}
}
}
}
IL void DFT(int *a, int n) {
NTT(a, n, root);
}
IL void IDFT(int *a, int n) {
NTT(a, n, root_inv);
int inv_n = quickPow(n, MOD - 2);
FOR(i, 0, n) {
a[i] = mul(a[i], inv_n);
}
}
IL void multiply(int *a, int n, int *b, int m, int *ret) {
int len = 0;
for (; 1 << len < n + m; ++ len);
static int x[1 << LOG], y[1 << LOG];
std::copy(a, a + n, x);
memset(x + n, 0, ((1 << len) - n) * sizeof (int));
std::copy(b, b + m, y);
memset(y + m, 0, ((1 << len) - m) * sizeof (int));
memset(ret, 0, (1 << len) * sizeof (int));
DFT(x, 1 << len);
DFT(y, 1 << len);
FOR(i, 0, 1 << len) {
ret[i] = mul(x[i], y[i]);
}
IDFT(ret, 1 << len);
memset(ret + n + m - 1, 0, ((1 << len) - n - m + 1) * sizeof (int));
}
void inverse(int *f, int *g, int t) {
if (t == 1) {
g[0] = quickPow(f[0], MOD - 2);
return;
}
inverse(f, g, (t + 1) >> 1);
int len = 0;
for (; 1 << len < t << 1; ++ len);
static int temp[1 << LOG];
std::copy(f, f + t, temp);
memset(temp + t, 0, ((1 << len) - t) * sizeof (int));
DFT(temp, 1 << len);
DFT(g, 1 << len);
FOR(i, 0, 1 << len) {
g[i] = mul(g[i], sub(2, mul(temp[i], g[i])));
}
IDFT(g, 1 << len);
memset(g + t, 0, ((1 << len) - t) * sizeof (int));
}
IL void reverse(int *f, int n) {
std::reverse(f, f + n);
}
IL void inc(int *f, int *g, int n, int *ret) {
FOR(i, 0, n) {
ret[i] = add(f[i], g[i]);
}
}
IL void dec(int *f, int *g, int n, int *ret) {
FOR(i, 0, n) {
ret[i] = sub(f[i], g[i]);
}
}
IL void divide(int *f, int n, int *g, int m, int *q, int *r) {
if (n < m) {
std::copy(f, f + n, r);
return;
}
reverse(f, n), reverse(g, m);
int len = 0;
for (; 1 << len < mymax((n - m + 1) << 1, n + 1); ++ len);
static int temp1[1 << LOG], temp2[1 << LOG];
memset(temp1, 0, (1 << len) * sizeof (int));
memset(temp2, 0, (1 << len) * sizeof (int));
std::copy(g, g + m, temp1);
inverse(temp1, temp2, n - m + 1);
multiply(f, n - m + 1, temp2, n - m + 1, q);
reverse(q, n - m + 1);
reverse(f, n), reverse(g, m);
multiply(g, m, q, n - m + 1, temp2);
dec(f, temp2, m - 1, r);
}
int pre_work[LOG][MAXN * 8];
void decoNTT(int *a, int level, int l, int r) {
if (l + 1 >= r) {
pre_work[level][l << 1] = sub(0, a[l]);
pre_work[level][l << 1 | 1] = 1;
return;
}
int mid = (l + r) >> 1;
decoNTT(a, level + 1, l, mid);
decoNTT(a, level + 1, mid, r);
static int temp[1 << LOG];
multiply(pre_work[level + 1] + (l << 1), mid - l + 1, pre_work[level + 1] + (mid << 1), r - mid + 1, temp);
std::copy(temp, temp + r - l + 1, pre_work[level] + (l << 1));
}
int ret_eval[LOG][1 << LOG];
void getEvaluation(int *f, int *g, int level, int l, int r, int len, int n) {
static int temp[1 << LOG];
int p = r - l;
divide(f, len, pre_work[level] + (l << 1), p + 1, temp, ret_eval[level] + l);
if (l + 1 >= r) {
g[l] = ret_eval[level][l];
return;
}
int mid = (l + r) >> 1;
getEvaluation(ret_eval[level] + l, g, level + 1, l, mid, mymin(p, n), n);
getEvaluation(ret_eval[level] + l, g, level + 1, mid, r, mymin(p, n), n);
}
IL void evaluate(int *a, int *f, int n, int m, int *g) {
decoNTT(a, 0, 0, m);
getEvaluation(f, g, 0, 0, m, n, n);
}
int ans[LOG][MAXN * 8];
void solve1(int *a, int level, int l, int r) {
if (l + 1 >= r) {
ans[level][l << 1] = a[l];
ans[level][l << 1 | 1] = 1;
return;
}
int mid = (l + r) >> 1;
solve1(a, level + 1, l, mid);
solve1(a, level + 1, mid, r);
static int temp[1 << LOG];
multiply(ans[level + 1] + (l << 1), mid - l + 1, ans[level + 1] + (mid << 1), r - mid + 1, temp);
std::copy(temp, temp + r - l + 1, ans[level] + (l << 1));
}
int ret[MAXN * 4];
void solve2(int level, int l, int r) {
if (l + 1 >= r) {
ret[l] = 1;
return;
}
int mid = (l + r) >> 1;
solve2(level + 1, l, mid);
solve2(level + 1, mid, r);
static int temp1[1 << LOG], temp2[1 << LOG];
multiply(ret + l, mid - l, ans[level + 1] + (mid << 1), r - mid + 1, temp1);
multiply(ans[level + 1] + (l << 1), mid - l + 1, ret + mid, r - mid, temp2);
inc(temp1, temp2, r - l, ret + l);
}
}
int a[MAXN * 4], x[MAXN * 4], y[MAXN * 4], z[MAXN * 4], f[MAXN * 4], g[MAXN * 4], to[MAXN], ans[MAXN];
int main() {
#ifndef ONLINE_JUDGE
freopen("p.in", "r", stdin);
freopen("p.out", "w", stdout);
#endif
int n, m;
scanf("%d%d", &n, &m);
Poly::init(n * 3 + 5);
int sum = 0;
FOR(i, 0, n) {
scanf("%d", &a[i]);
sum = add(sum, a[i]);
}
Poly::solve1(a, 0, 0, n);
Poly::solve2(0, 0, n);
int a = 1, b = 0, c = 0, d = 1, cnt = 0;
FOR(i, 0, m) {
int opt;
scanf("%d", &opt);
if (opt == 1) {
int x;
scanf("%d", &x);
a = add(a, mul(c, x)), b = add(b, mul(d, x));
} else {
std::swap(a, c), std::swap(b, d);
}
if (!c) {
ans[i] = mul(add(mul(sum, a), mul(b, n)), quickPow(d, MOD - 2));
continue;
}
int inv = quickPow(c, MOD - 2);
x[cnt] = mul(a, inv), y[cnt] = mul(sub(b, mul(d, x[cnt])), inv), z[cnt] = mul(d, inv);
to[cnt ++] = i;
}
Poly::evaluate(z, Poly::ans[0], n + 1, cnt, f);
Poly::evaluate(z, Poly::ret, n, cnt, g);
FOR(i, 0, cnt) {
ans[to[i]] = add(mul(x[i], n), mul(y[i], g[i], quickPow(f[i], MOD - 2)));
}
FOR(i, 0, m) {
printf("%d\n", ans[i]);
}
return 0;
}