T1004 游戏(HDU 7460)

注意到对于两个人,他们 \(t\) 轮后能力值相同的概率只与他们初始时的能力差有关,所以我们先 \(\text{FFT}\) 求出 \(|a_i - a_j| = k\) 的 \((i, j)\) 对数。

构造多项式 \(F(x) = (p_1 x^2 + p_2 + p_3x)\),其中 \(p_1, p_2, p_3\),分别表示在一轮中两个人相对能力值变化为 \(+1/-1/0\) 的概率,这三个数容易用 \(n\) 表示,我们现在的任务是 \(\forall k \in [0, V)\),求 \([x^{t + k}] F(x)^t\)。

令 \(G(x) = F(x)^t\),考虑对 \(G\) 求导,我们有 \(G'(x) = t \times F'(x) \times F(x)^{t - 1} \iff G'(x) \times F(x) = t \times F'(x) \times G(x)\),将 \(F\) 和 \(F'\) 展开可得 \(G'(x) \times (p_1 x^2 + p_2 + p_3x) = t \times (2p_1x + p_3) \times G(x)\),取 \(G\) 的 \(i\) 次项系数即可得到 \(G\) 的系数的递推式。

时间复杂度 \(O(V \log V + t)\)。

Code
#include <iostream>
#include <vector>
#include <algorithm>
#include <complex>
#include <cmath> using namespace std;
using LL = long long;
using Cp = complex<double>; const int N = 1e6 + 5, T = 2e7 + 5;
const int Mod = 998244353; int power (int x, int y = Mod - 2) {
int res = 1;
while (y) {
if (y & 1) {
res = 1ll * res * x % Mod;
}
x = 1ll * x * x % Mod;
y >>= 1;
}
return res;
} int m, t;
int inv[T], g[T];
LL a[N]; namespace FFT {
const double pi = acos(-1);
int len = 1;
vector<int> r; void FFT (vector<Cp> &a, int v) {
for (int i = 0; i < len; ++i) {
if (i < r[i]) {
swap(a[i], a[r[i]]);
}
}
for (int i = 1; i < len; i <<= 1) {
for (int j = 0; j < len; j += (i << 1)) {
for (int k = 0; k < i; ++k) {
Cp p = a[j + k], q = Cp(cos(pi * k / i), sin(pi * k / i) * v) * a[j + k + i];
a[j + k] = p + q, a[j + k + i] = p - q;
}
}
}
} vector<LL> convolution (vector<int> &a, vector<int> &b) {
int n = a.size() - 1, m = b.size() - 1;
for (; len <= n + m; len <<= 1) {
}
a.resize(len), b.resize(len), r.resize(len);
vector<Cp> A(len);
for (int i = 0; i < len; ++i) {
A[i] = Cp(a[i], b[i]);
r[i] = (r[i >> 1] >> 1) | (i & 1) * (len >> 1);
}
FFT(A, 1);
for (int i = 0; i < len; ++i) {
A[i] *= A[i];
}
FFT(A, -1);
vector<LL> res(n + m + 1);
for (int i = 0; i <= n + m; ++i) {
res[i] = LL(A[i].imag() / len / 2 + 0.5);
}
return res;
}
} int main () {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
inv[1] = 1;
for (int i = 2; i < T; ++i) {
inv[i] = 1ll * (Mod - Mod / i) * inv[Mod % i] % Mod;
}
int tmpn;
cin >> tmpn >> t;
vector<int> arr(tmpn);
for (int i = 0; i < tmpn; ++i) {
cin >> arr[i];
m = max(m, arr[i]);
}
vector<int> c(m + 1);
for (auto x : arr) {
++c[x];
}
for (auto t : c) {
a[0] += 1ll * (t - 1) * t / 2;
}
vector<int> _c = c;
reverse(_c.begin(), _c.end());
vector<LL> z = FFT::convolution(c, _c);
for (int i = 1; i < m; ++i) {
a[i] += z[i + m];
}
--m;
int p1 = 2ll * (tmpn - 2) * inv[tmpn] % Mod * inv[tmpn - 1] % Mod, p2 = p1, p3 = (1 - p1 * 2 + Mod * 2) % Mod;
int p1i = 1ll * power(p1) * (Mod - 1) % Mod;
g[t * 2] = power(p1, t);
if (t) g[t * 2 - 1] = 1ll * power(p1, t - 1) * p3 % Mod * t % Mod;
for (int i = t * 2 - 1; i >= t; --i) {
g[i - 1] = ((1ll * (t - i + Mod) * p3 % Mod * g[i] - 1ll * (i + 1) * p2 % Mod * g[i + 1] + 1ll * Mod * Mod) % Mod) * inv[t * 2 + 1 - i] % Mod * p1i % Mod;
}
int ans = 0;
for (int i = 0; i <= min(t, m); ++i) {
ans = (ans + 1ll * g[i + t] * (a[i] % Mod)) % Mod;
}
cout << ans << '\n';
return 0;
}

T1005 数论(HDU 7461)

考虑固定一个端点向左/右扫,可以得到 \(O(\log n)\) 个 \(\gcd\) 相同的段(\(\gcd\) 每次变化至少减半),每段形如 \((g, l, r, t)\),表示一个端点为 \(t\),另一个端点在 \([l, r]\) 中,这样构成的区间都满足 \(\gcd = g\),总段数 \(O(n \log n)\),找段考虑二分 + ST 表,时间复杂度 \(O(n \log^2 n)\)。

对答案进行容斥,算出总方案数和不包含 \(i\) 的方案数,不包含一个数又可以拆成一段前缀和一段后缀任选,所以我们只需对前缀和后缀分别做 \(\text{dp}\) 即可。

对于前缀而言,我们枚举 \(\gcd\) 然后分别算贡献,对于某个 \(\gcd = g\) 有若干段 \((l, r, t)\),我们按 \(t\) 排序,设 \(f_i\) 表示在 \([1, i]\) 中选若干满足 \(\gcd = g\) 的不交区间,最后一个区间右端点为 \(i\) 的方案数,转移方程是 \(f_t = \sum\limits_{i = l}^{r} \sum\limits_{j = 0}^{i - 1} f_j\)。考虑一个 \(f_j\) 的贡献,对于 \(j < l\),\(f_j\) 系数为 \(r - l + 1\),对于 \(j \in [l, r]\),\(f_j\) 系数构成公差为 \(-1\),末项为 \(0\) 的等差数列。相当于单点修改,区间和,区间等差数列加权和,线段树容易维护。

后缀类似,设 \(g_i\) 表示在 \([i, n]\) 中选若干满足 \(\gcd = g\) 的不交区间,第一个区间以 \(i\) 为左端点的方案数,再开一棵线段树维护即可。

时间复杂度 \(O(n \log^2 n)\)。

Code
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
#include <chrono>
#include <cassert> #define lc (k << 1)
#define rc ((k << 1) | 1) using namespace std;
using LL = long long;
using uLL = unsigned long long; uLL Get_time () { return chrono::steady_clock::now().time_since_epoch().count(); } const int N = 1e5 + 5, M = 17;
const int Mod = 998244353; int n, allsum;
int a[N], st[N][M], diff[N]; struct Tr {
int l, r, t;
}; namespace Pre_Seg {
const int T = N * 4; struct Tree {
int sum[T], rsum[T], len[T]; void Build (int k, int L = 0, int R = n) {
len[k] = R - L + 1;
if (L == R) return;
int mid = (L + R) >> 1;
Build(lc, L, mid);
Build(rc, mid + 1, R);
} void Modify (int k, int x, int y, int L = 0, int R = n) {
if (L == R) {
sum[k] = y;
return;
}
int mid = (L + R) >> 1;
if (x <= mid) {
Modify(lc, x, y, L, mid);
}
else {
Modify(rc, x, y, mid + 1, R);
}
sum[k] = (sum[lc] + sum[rc]) % Mod;
rsum[k] = (rsum[lc] + rsum[rc] + 1ll * sum[lc] * len[rc]) % Mod;
} LL Query_sum (int k, int l, int r, int L = 0, int R = n) {
if (l > r) return 0;
if (l <= L && r >= R) {
return sum[k];
}
int mid = (L + R) >> 1;
LL res = 0;
if (l <= mid) {
res = (res + Query_sum(lc, l, r, L, mid));
}
if (r > mid) {
res = (res + Query_sum(rc, l, r, mid + 1, R));
}
return res;
} LL Query_rsum (int k, int l, int r, int L = 0, int R = n) {
if (l <= L && r >= R) {
return (rsum[k] + 1ll * (r - R) * sum[k]) % Mod;
}
int mid = (L + R) >> 1;
LL res = 0;
if (l <= mid) {
res = (res + Query_rsum(lc, l, r, L, mid));
}
if (r > mid) {
res = (res + Query_rsum(rc, l, r, mid + 1, R));
}
return res;
}
};
} namespace Suf_Seg {
const int T = N * 4; struct Tree {
int sum[T], rsum[T], len[T]; void Build (int k, int L = 1, int R = n + 1) {
len[k] = R - L + 1;
if (L == R) return;
int mid = (L + R) >> 1;
Build(lc, L, mid);
Build(rc, mid + 1, R);
} void Modify (int k, int x, int y, int L = 1, int R = n + 1) {
if (L == R) {
sum[k] = y;
return;
}
int mid = (L + R) >> 1;
if (x <= mid) {
Modify(lc, x, y, L, mid);
}
else {
Modify(rc, x, y, mid + 1, R);
}
sum[k] = (sum[lc] + sum[rc]) % Mod;
rsum[k] = (rsum[lc] + rsum[rc] + 1ll * len[lc] * sum[rc]) % Mod;
} LL Query_sum (int k, int l, int r, int L = 1, int R = n + 1) {
if (l > r) return 0;
if (l <= L && r >= R) {
return sum[k];
}
int mid = (L + R) >> 1;
LL res = 0;
if (l <= mid) {
res = (res + Query_sum(lc, l, r, L, mid));
}
if (r > mid) {
res = (res + Query_sum(rc, l, r, mid + 1, R));
}
return res;
} LL Query_rsum (int k, int l, int r, int L = 1, int R = n + 1) {
if (l <= L && r >= R) {
return (rsum[k] + 1ll * (L - l) * sum[k]) % Mod;
}
int mid = (L + R) >> 1;
LL res = 0;
if (l <= mid) {
res = (res + Query_rsum(lc, l, r, L, mid));
}
if (r > mid) {
res = (res + Query_rsum(rc, l, r, mid + 1, R));
}
return res;
}
};
} Pre_Seg::Tree pret;
Suf_Seg::Tree suft; signed main () {
// freopen("tmp.in", "r", stdin);
// freopen("1005.out", "w", stdout);
cin.tie(0)->sync_with_stdio(0);
uLL st0 = Get_time();
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
pret.Build(1), pret.Modify(1, 0, 1);
suft.Build(1), suft.Modify(1, n + 1, 1);
for (int i = 1; i <= n; ++i) {
st[i][0] = a[i];
}
for (int k = 1; k < M; ++k) {
for (int i = 1; i + (1 << k) - 1 <= n; ++i) {
st[i][k] = __gcd(st[i][k - 1], st[i + (1 << (k - 1))][k - 1]);
}
}
auto Query = [&](int l, int r) -> int {
int k = log2(r - l + 1);
return __gcd(st[l][k], st[r - (1 << k) + 1][k]);
};
map<int, vector<Tr>> mpre;
map<int, vector<Tr>> msuf;
for (int i = 1; i <= n; ++i) {
for (int p = i, l = 1, r = p; p; p = l - 1, l = 1, r = p) {
int g = Query(p, i);
while (l <= r) {
int mid = (l + r) >> 1;
if (Query(mid, i) == g) {
r = mid - 1;
}
else {
l = mid + 1;
}
}
auto it = mpre.find(g);
if (it == mpre.end()) {
mpre.insert({g, vector<Tr>{{l, p, i}}});
}
else {
it->second.push_back({l, p, i});
}
}
for (int p = i, l = p, r = n; p <= n; p = r + 1, l = p, r = n) {
int g = Query(i, p);
while (l <= r) {
int mid = (l + r) >> 1;
if (Query(i, mid) == g) {
l = mid + 1;
}
else {
r = mid - 1;
}
}
auto it = msuf.find(g);
if (it == msuf.end()) {
msuf.insert({g, vector<Tr>{{p, r, i}}});
}
else {
it->second.push_back({p, r, i});
}
}
}
for (auto ipre = mpre.begin(), isuf = msuf.begin(); ipre != mpre.end(); ++ipre, ++isuf) {
assert(ipre->first == isuf->first);
vector<Tr> vp = ipre->second, sp = isuf->second;
sort(vp.begin(), vp.end(), [&](Tr i, Tr j) -> bool {
return i.t < j.t;
});
sort(sp.begin(), sp.end(), [&](Tr i, Tr j) -> bool {
return i.t > j.t;
});
vector<int> dpoint;
for (auto i : vp) {
dpoint.push_back(i.t);
int f = (pret.Query_sum(1, 0, i.l - 1) % Mod * (i.r - i.l + 1) + pret.Query_rsum(1, i.l, i.r)) % Mod;
pret.Modify(1, i.t, f);
allsum = (allsum + f) % Mod;
}
for (auto i : sp) {
dpoint.push_back(i.t);
int f = (suft.Query_sum(1, i.r + 1, n + 1) % Mod * (i.r - i.l + 1) + suft.Query_rsum(1, i.l, i.r)) % Mod;
suft.Modify(1, i.t, f);
}
sort(dpoint.begin(), dpoint.end());
dpoint.resize(unique(dpoint.begin(), dpoint.end()) - dpoint.begin());
int la = 0;
auto Range_add = [&](int l, int r) -> void {
if (l > r) return;
int x = ((pret.Query_sum(1, 1, l - 1) % Mod + 1) * (suft.Query_sum(1, l + 1, n) % Mod + 1) % Mod - 1 + Mod) % Mod;
diff[l] = (diff[l] + x) % Mod;
diff[r + 1] = (diff[r + 1] - x + Mod) % Mod;
};
for (auto i : dpoint) {
Range_add(la + 1, i - 1);
Range_add(i, i);
la = i;
}
Range_add(la + 1, n);
for (auto i : vp) {
pret.Modify(1, i.t, 0);
}
for (auto i : sp) {
suft.Modify(1, i.t, 0);
}
}
for (int i = 1; i <= n; ++i) {
diff[i] = (diff[i] + diff[i - 1]) % Mod;
}
for (int i = 1; i <= n; ++i) {
cout << (allsum - diff[i] + Mod) % Mod << ' ';
}
cout << '\n';
uLL ed0 = Get_time();
// cerr << "Time = " << (ed0 - st0) / int(1e6) << '\n';
return 0;
}

T1006 字符串(HDU 7462)

不会。

T1009 圣芙蕾雅(HDU 7465)

不会。

T1010 绘世之卷(HDU 7466)

首先带删除肯定是不好做的,考虑线段树分治一下,变成插入和撤销,这样我们只需在加入一个数时,算它和其他数的贡献。

根号分治,令 \(d = \lfloor \sqrt n \rfloor\)。注意到当集合大小 \(|S| > d\) 时,答案 \(\le d\),证明:容易说明一定存在一对 \((x, y)\) 满足 \(1 \le y - x \le d\),如果 \(x \le d\) 那么用 \(x\) 做被除数,否则用 \(y\) 做被除数即可。

当 \(|S| \le d\) 时直接暴力和每个元素匹配算贡献。当 \(|S| > d\) 时,分类讨论,假设当前加入的是 \(x\)。

  • 若 \(ky + r = x \iff ky = x - r\),枚举 \(r\),在插入 \(y\) 时预处理 \(k \in [0, d]\) 即可。
  • 若 \(kx + r = y\),枚举 \(k\),只需找到 \(kx\) 的前驱,插入一个数 \(y\) 时修改 \([y, y + d]\) 的前驱即可。

两种修改操作都方便撤销。

时间复杂度 \(O(n \sqrt n \log n)\)。

Code
#include <iostream>
#include <vector>
#include <set>
#include <cmath> using namespace std; #define lc (k << 1)
#define rc ((k << 1) | 1) const int N = 5e4 + 5, Inf = 1e9, T = N * 4;
const int S = 1e6; int n, d, q, cur, ans[N], pre[N], mik[N];
vector<int> vec[T];
set<int> st;
int len1, len2;
pair<int, int> stpre[S], stmik[S]; void Add (int k, int l, int r, int x, int L = 1, int R = q) {
if (l <= L && r >= R) {
vec[k].push_back(x);
return;
}
int mid = (L + R) >> 1;
if (l <= mid) {
Add(lc, l, r, x, L, mid);
}
if (r > mid) {
Add(rc, l, r, x, mid + 1, R);
}
} void Solve (int k, int L = 1, int R = q) {
int lst = cur, tmp1 = len1, tmp2 = len2;
for (auto x : vec[k]) {
if (st.size() >= d) {
for (int r = 0; r <= d && x - r; ++r) {
cur = min(cur, mik[x - r] + r);
}
for (int k = 0; k <= d && x * k <= n; ++k) {
cur = min(cur, x * k - pre[x * k] + k);
}
}
else {
for (auto y : st) {
cur = min(cur, min(x / y + x % y, y / x + y % x));
}
}
st.insert(x);
for (int k = 0; k <= d && x * k <= n; ++k) {
if (k < mik[x * k]) {
stmik[++len1] = {x * k, mik[x * k]};
mik[x * k] = k;
}
}
for (int i = x; i <= min(n, x + d); ++i) {
if (x > pre[i]) {
stpre[++len2] = {i, pre[i]};
pre[i] = x;
}
else {
break;
}
}
}
if (L == R)
ans[L] = cur;
else {
int mid = (L + R) >> 1;
Solve(lc, L, mid);
Solve(rc, mid + 1, R);
}
cur = lst;
for (auto x : vec[k])
st.erase(x);
for (; len1 > tmp1; --len1)
mik[stmik[len1].first] = stmik[len1].second;
for (; len2 > tmp2; --len2)
pre[stpre[len2].first] = stpre[len2].second;
} int main () {
cin.tie(0)->sync_with_stdio(0);
int T;
cin >> T;
while (T--) {
cin >> n >> q, d = sqrt(n);
vector<int> occ(n + 1, -1);
fill(vec + 1, vec + q * 4 + 1, vector<int>());
for (int o, x, i = 1; i <= q; ++i) {
cin >> o >> x;
if (o == 0) {
Add(1, occ[x], i - 1, x);
occ[x] = -1;
}
else {
occ[x] = i;
}
}
for (int i = 1; i <= n; ++i) {
if (occ[i] != -1) {
Add(1, occ[i], q, i);
}
}
fill(mik + 1, mik + n + 1, Inf);
fill(pre, pre + n + 1, -Inf);
cur = N, Solve(1);
for (int i = 1; i <= q; ++i) {
cout << (ans[i] == N ? -1 : ans[i]) << '\n';
}
}
return 0;
}

HDU-ACM 2024 Day3的更多相关文章

  1. hdu acm 1028 数字拆分Ignatius and the Princess III

    Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  2. HDU ACM 题目分类

    模拟题, 枚举1002 1004 1013 1015 1017 1020 1022 1029 1031 1033 1034 1035 1036 1037 1039 1042 1047 1048 104 ...

  3. hdu acm 1166 敌兵布阵 (线段树)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  4. hdu acm 2082 找单词

    找单词 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  5. HDU ACM 1325 / POJ 1308 Is It A Tree?

    Is It A Tree? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  6. HDU ACM 1134 Game of Connections / 1130 How Many Trees?(卡特兰数)

    [题目链接]http://acm.hdu.edu.cn/showproblem.php?pid=1134 [解题背景]这题不会做,自己推公式推了一段时间,将n=3和n=4的情况列出来了,只发现第n项与 ...

  7. HDU ACM Eight

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 解题背景: 看到八数码问题,没有任何的想法,偶然在翻看以前做的题的时候发现解决过类似的一道题,不 ...

  8. HDU ACM 1690 Bus System (SPFA)

    Bus System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  9. HDU ACM 1224 Free DIY Tour (SPFA)

    Free DIY Tour Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  10. HDU ACM 1869 六度分离(Floyd)

    六度分离 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

随机推荐

  1. 【JSON】JavaScript Object Notation JS对象表示规则

    什么是 JSON? JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式. 易于人阅读和编写.同时也易于机器解析和生成. JSON采用完全独立于语言的文本格式 ...

  2. 【JS】01 JavaScript概述

    感觉上来谈这个前端,结构的部分是使用了标签语言定义了页面的文档内容 但是XML和HTML的功能完全相反,XML被用于存储信息,而HTML则用于定义网页结构,辅助其他内容渲染 然后C3又可以通过选择器这 ...

  3. 【Mycat】01 概述

    什么是Mycat? 数据库中间件 中间件:是一类连接软件组件和应用的计算机软件,以便于软件各部件之间的沟通. 例子:Tomcat,web中间件. 数据库中间件:连接java应用程序和数据库 为什么要用 ...

  4. 大语言模型内部运行原理 | LLM | 词向量 | Transformer | 注意力机制 | 前馈网络 | 反向传播

    https://www.understandingai.org/p/large-language-models-explained-with https://arxiv.org/abs/1905.05 ...

  5. MindSpore 自动微分

    代码原地址: https://www.mindspore.cn/tutorial/zh-CN/r1.2/autograd.html MindSpore计算一阶导数方法  mindspore.ops.G ...

  6. MindSpore计算框架如何发布训练好的模型到官方模型仓库MindSpore_Hub上

    相关官方资料: https://www.mindspore.cn/tutorial/training/zh-CN/r1.2/use/publish_model.html 参考地址: https://g ...

  7. 【转载】 机器学习数据可视化 (t-SNE 使用指南)—— Why You Are Using t-SNE Wrong

    原文地址: https://towardsdatascience.com/why-you-are-using-t-sne-wrong-502412aab0c0 ==================== ...

  8. 【转载】 深度学习——Xavier初始化方法

    版权声明:本文为CSDN博主「shuzfan」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/shuzfan/a ...

  9. mybatis-plus自动生成代码

    1.背景 本教程将介绍如何使用 mybatis-plus 工具自动给我们生成 Controller.Service.Entity.Mapper.Mapper.xml 层代码; 给出一个便于于学习理解的 ...

  10. Redis存储数组

    建议使用PHP自带的序列化函数serialize和unserialize函数 <?php class MyRedis{ private static $handler; private stat ...