T1009 数位的关系(HDU 7441)

考虑 \(l = r\) 的情况,此时只要计算一个数字,我们将其展开为一个字符串 \(S\)。设 \(f_{i, j, k}\) 表示考虑了 \(S\) 的前 \(i\) 位,选出了 \(j\) 个数字加入子序列,最后一个加入子序列的数字是 \(k\) 的方案数,转移平凡。

拓展到 \(l \neq r\),经典地将答案差分为 \(f(r + 1) - f(l)\),其中 \(f(i)\) 表示 \([1, i)\) 中的答案。设 \(g_{i, j, k, 0/1}\) 表示任意填 \(i\) 位,选出子序列的 \([j, |R| + 1]\) 部分,最后一个数字为 \(k\),是否(\(0/1\))能填 \(0\) 的方案数。

其他就是数位 \(\text{dp}\) 套路了,假设要算 \(f(x)\),\(x\) 作为字符串长度为 \(len\)。不足 \(len\) 位答案可直接用 \(g\) 表示;恰好 \(len\) 位枚举第一个 \(<x\) 的位置 \(i\),第 \([1, i)\) 位必须和 \(x\) 相同,答案可用 \(f\) 表示,第 \(i\) 位在 \([0, x_i)\) 中枚举,第 \([i + 1, len]\) 位任意填,答案可用 \(g\) 表示,三段拼起来即可。

Code
#include <iostream>
#include <cstring>
#include <vector> using namespace std; const int N = 505;
const int Mod = 998244353; int R, dig[N];
string rs;
int f[N][N][10][10], g[2][N][N][10]; bool valid (int x, char o, int y) {
if (o == '=') return x == y;
if (o == '<') return x < y;
return x > y;
} int dp (int i, int j, int k, int l) {
if (!j) return k == R;
if (g[i][j][k][l] != -1) return g[i][j][k][l];
int res = 0;
for (int d = !i; d <= 9; ++d) {
if (!k || valid(l, rs[k], d)) {
res = (res + dp(1, j - 1, k + 1, d)) % Mod;
}
res = (res + dp(1, j - 1, k, l)) % Mod;
}
return g[i][j][k][l] = res;
} int calc_pre (string s) {
int len = s.size();
string tmp = s;
for (int i = 1; i <= len; ++i) {
dig[i] = tmp.back() - '0';
tmp.pop_back();
}
int res = 0;
for (int i = 1; i < len; ++i) {
res = (res + dp(0, i, 0, 0)) % Mod;
}
s = " " + s;
s[0] = 0;
for (int i = 1; i <= len; ++i) {
s[i] -= '0';
}
memset(f, 0, sizeof(f));
f[0][0][0][0] = 1;
for (int i = 1; i <= len; ++i) {
for (int d = 0; d <= 9; ++d) {
for (int j = 0; j <= R; ++j) {
for (int k = 0; k <= 9; ++k) {
f[i][j][k][d] = (f[i][j][k][d] + f[i - 1][j][k][s[i - 1]]) % Mod;
if (j < R && (!j || valid(k, rs[j], d))) {
f[i][j + 1][d][d] = (f[i][j + 1][d][d] + f[i - 1][j][k][s[i - 1]]) % Mod;
}
}
}
}
}
for (int i = len; i; --i) {
for (int j = (i == len); j < dig[i]; ++j) {
for (int k = 0; k <= R; ++k) {
for (int l = 0; l <= 9; ++l) {
res = (res + 1ll * f[len - i + 1][k][l][j] * dp(1, i - 1, k, l)) % Mod;
}
}
}
}
return res;
} void add (string &s) {
int len = s.size();
for (int i = len - 1; ~i; --i) {
if (s[i] < '9') {
++s[i];
break;
}
else {
s[i] = '0';
}
}
if (s[0] == '0') s = "1" + s;
} int main () {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while (T--) {
string l, r;
cin >> l >> r >> rs, add(r);
R = rs.size() + 1, rs = " " + rs;
memset(g, -1, sizeof(g));
cout << (calc_pre(r) - calc_pre(l) + Mod) % Mod << '\n';
}
return 0;
}

T1010 众数(HDU 7442)

注意到数据随机,我们猜测答案极大概率是大数,考虑套用 P5926 [JSOI2009] 面试的考验 的做法,取前 \(D = 600\) 大的数,算一个数对一次询问的贡献。

维护当前未被删除的数构成的连续段,每次删除一个未被删除的最大数 \(x\) 并算其贡献。考虑 \(x\) 所在连续段中任意一个区间对 \(x\) 都有贡献,将连续段的限制和询问区间的限制取交,方案数好算。

现在删除了前 \(D\) 大的数,对于每个询问初步得到了一个 \(ans\),我们想知道这个询问是否可能出现更优的解。我们将这个询问覆盖的连续段拿出来(连续段数 \(O(D)\),可以接受),和询问区间取交,设连续段取交后长度为 \(len_{1 \sim m}\),若 \(\sum \limits_{i = 1}^{m} \frac{len_i(len_i + 1)}{2} > ans\) 则说明这个询问在可能有更优解,单调栈线性暴力即可。

由于数据随机,根据前面的猜想,我们认为需要暴力的区间不会很多。

时间复杂度 \(O(Dn + ?)\),其中 \(?\) 是需要暴力的区间的总长度,最坏情况下(数据可不随机) \(? = O(n^2)\),但算法的正确性可保证。

Code
#include <iostream>
#include <stack>
#include <unordered_map>
#include <vector>
#include <algorithm> using namespace std;
using Vec = vector<int>;
using LL = long long; const int N = 2e5 + 5, D = 600; int n, q;
int a[N], L[N], R[N], mx[N];
int ql[N], qr[N];
LL mp[N], tmpc[N], mxc[N];
vector<int> vec[N], now; int query (int l, int r) {
stack<int> s;
fill(L + l, L + r + 1, l - 1);
fill(R + l, R + r + 1, r + 1);
for (int i = l; i <= r; ++i) {
while (!s.empty() && a[i] > a[s.top()]) {
R[s.top()] = i;
s.pop();
}
if (!s.empty()) L[i] = s.top();
s.push(i);
}
for (int i = l; i <= r; ++i) {
mp[a[i]] += 1ll * (i - L[i]) * (R[i] - i);
}
int val = 0;
LL mx = -1;
for (int i = l; i <= r; ++i) {
if (mp[a[i]] > mx || mp[a[i]] == mx && a[i] > val) {
val = a[i], mx = mp[val];
}
mp[a[i]] = 0;
}
return val;
} int main () {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n >> q;
fill(vec + 1, vec + n + 1, vector<int>()), now.clear();
fill(mx + 1, mx + q + 1, 0);
fill(mxc + 1, mxc + q + 1, 0);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
vec[a[i]].push_back(i);
}
for (int i = 1; i <= q; ++i) {
cin >> ql[i] >> qr[i];
}
for (int i = n, c = 0; i; --i) {
if (vec[i].empty()) continue;
if (c + vec[i].size() > D) break;
c += vec[i].size();
fill(tmpc + 1, tmpc + q + 1, 0);
for (int x = 0, y = 0; x < vec[i].size(); ++x) {
int pos = vec[i][x];
while (y < now.size() && now[y] < pos) {
++y;
}
int tL = !y ? 0 : now[y - 1], tR = n + 1;
if (y != now.size()) tR = min(tR, now[y]);
if (x != vec[i].size() - 1) tR = min(tR, vec[i][x + 1]);
for (int j = 1; j <= q; ++j) {
int lL = max(tL, ql[j] - 1), lR = min(tR, qr[j] + 1);
if (lL <= pos && pos <= lR) {
tmpc[j] += 1ll * (pos - lL) * (lR - pos);
}
}
}
for (int j = 1; j <= q; ++j) {
if (tmpc[j] > mxc[j]) {
mxc[j] = tmpc[j], mx[j] = i;
}
}
Vec tmp;
auto merge = [&](Vec a, Vec b) -> void {
tmp.resize(a.size() + b.size());
for (int i = 0, j = 0; i < a.size() || j < b.size(); ) {
if (i < a.size() && (j == b.size() || a[i] < b[j])) {
tmp[i + j] = a[i], ++i;
}
else {
tmp[i + j] = b[j], ++j;
}
}
};
merge(now, vec[i]), now = tmp;
}
now.push_back(0), now.push_back(n + 1);
sort(now.begin(), now.end());
LL ans = 0;
for (int i = 1; i <= q; ++i) {
LL gmax = 0;
for (auto it = now.begin(); next(it) != now.end(); ++it) {
int L = max(*it + 1, ql[i]), R = min(*next(it) - 1, qr[i]), len = max(R - L + 1, 0);
gmax += 1ll * len * (len + 1) / 2;
}
if (gmax > mxc[i]) mx[i] = query(ql[i], qr[i]);
ans ^= 1ll * mx[i] * i;
}
cout << ans << '\n';
}
return 0;
}

T1011 树上的 mex(HDU 7443)

首先可以二分 \(\text{mex} = k\),题意相当于求覆盖值域 \([0, k)\) 的路径数。

考虑同时覆盖一段值域不好做,转化成求不覆盖某一个值域的并集。我们枚举权值 \(v\),可以定位到树上点权为 \(v\) 的若干点,若这条路径不包含其中任何一个点则肯定不合法。

观察不合法的点对长什么样。我们发现对于一个 \(v\),将所有点权为 \(v\) 的点建虚树(可以在虚树中添加虚拟点作为根),对于一个虚树上的点 \(u\),设它的虚儿子集合为 \(Son_u\),在原树上的子树内点集为 \(Sub_u\),那么在点集 \(V = Sub_u - {u} - \bigcup\limits_{v \in Son_u} Sub_v\) 中的点两两配对都不合法。

观察到 \(V\) 在 \(\text{dfs}\) 序上可以划分为 \(O(Son_u)\) 个区间,两两配对形成 \(O((Son_u)^2)\) 个矩形,由于权值为 \(v\) 的点集中在一条路径上,我们有 \(|Son_u| \le 2\),所以对于一个 \(u\),矩形数量是 \(O(1)\) 的,总数就是 \(O(n)\) 的,扫描线 + 线段树算覆盖面积即可。

时间复杂度 \(O(n \log^2 n)\),常数较大。

Code (被卡常而无法通过)
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
#pragma GCC optimize("Ofast") using namespace std;
using Pr = pair<int, int>;
using LL = long long; const int N = 7e4 + 5; struct Rec {
int x, l, r, v;
}; int n;
int a[N], siz[N], rmp[N], dfn[N], now;
vector<int> e[N], vec[N];
vector<Rec> rv;
int lc[N], rc[N]; inline bool in_subtree (int u, int v) { return dfn[u] <= dfn[v] && dfn[v] < dfn[u] + siz[u]; } void build (int u, int r) {
siz[u] = 1;
rmp[dfn[u] = ++now] = u;
for (auto v : e[u]) {
if (v != r) {
build(v, u);
siz[u] += siz[v];
}
}
} void add_rec (int col) {
if (vec[col].empty()) {
rv.push_back((Rec){1, 1, n, 1});
rv.push_back((Rec){n + 1, 1, n, -1});
return;
}
int t1 = 0, t2 = 0;
for (auto u : vec[col]) {
lc[u] = rc[u] = 0;
if (t1 && in_subtree(u, t1)) {
lc[u] = t1, t1 = 0;
}
if (t2 && in_subtree(u, t2)) {
(!lc[u] ? lc[u] : rc[u]) = t2, t2 = 0;
}
if (dfn[lc[u]] > dfn[rc[u]]) swap(lc[u], rc[u]);
(!t1 ? t1 : t2) = u;
}
auto dfs = [&](auto &dfs, int u) -> void {
for (auto v : e[u]) if (dfn[v] > dfn[u]) {
vector<Pr> ve;
int vL = dfn[v], vR = dfn[v] + siz[v] - 1;
auto add = [&](int l, int r) -> void {
if (l > r) return;
ve.push_back({l, r});
};
auto cut = [&](int l, int r) -> void {
add(vL, l - 1), vL = r + 1;
};
if (lc[u] && in_subtree(v, lc[u])) cut(dfn[lc[u]], dfn[lc[u]] + siz[lc[u]] - 1);
if (rc[u] && in_subtree(v, rc[u])) cut(dfn[rc[u]], dfn[rc[u]] + siz[rc[u]] - 1);
add(vL, vR);
for (int i = 0; i < ve.size(); ++i) {
for (int j = 0; j < ve.size(); ++j) {
Rec tmpr1 = (Rec){ve[i].first, ve[j].first, ve[j].second, 1};
Rec tmpr2 = (Rec){ve[i].second + 1, ve[j].first, ve[j].second, -1};
rv.push_back(tmpr1), rv.push_back(tmpr2);
}
}
}
if (lc[u]) dfs(dfs, lc[u]);
if (rc[u]) dfs(dfs, rc[u]);
};
dfs(dfs, 0);
} namespace Seg {
#define lc (k << 1)
#define rc ((k << 1) | 1)
const int T = N * 4; int tag[T], cnt[T]; inline void pushup (int k, int L, int R) {
cnt[k] = (tag[k] ? R - L + 1 : (L != R ? cnt[lc] + cnt[rc] : 0));
} void add (int k, int l, int r, int v, int L = 1, int R = n) {
if (l <= L && r >= R) {
tag[k] += v;
}
else {
int mid = (L + R) >> 1;
if (l <= mid) {
add(lc, l, r, v, L, mid);
}
if (r > mid) {
add(rc, l, r, v, mid + 1, R);
}
}
pushup(k, L, R);
} inline void add_ (int l, int r, int v) { add(1, l, r, v); }
inline int count_ () { return cnt[1]; } #undef lc
#undef rc
} LL check (int goal) {
LL res = 1ll * n * n;
rv.clear();
for (int i = 0; i <= goal; ++i) {
add_rec(i);
}
auto cmp = [&](const Rec &a, const Rec &b) -> bool {
return a.x < b.x;
};
stable_sort(rv.begin(), rv.end(), cmp);
auto it = rv.begin();
for (int x = 1; x <= n + 1; ++x) {
while (it != rv.end() && it->x == x) {
Seg::add_(it->l, it->r, it->v);
++it;
}
res -= Seg::count_();
}
return res;
} int main () {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n;
fill(e + 1, e + n + 1, vector<int>());
fill(vec, vec + n + 1, vector<int>());
for (int i = 1; i <= n; ++i) {
cin >> a[i];
vec[a[i]].push_back(i);
}
for (int i = 1, u, v; i < n; ++i) {
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
now = 0, build(1, 0), siz[0] = n + 1, e[0].push_back(1);
for (int i = 0; i < n; ++i) {
vec[i].push_back(0);
auto cmp = [&](int i, int j) -> bool {
return siz[i] < siz[j];
};
stable_sort(vec[i].begin(), vec[i].end(), cmp);
}
int l = 0, r = n - 1;
LL rans = 0;
while (l <= r) {
int mid = (l + r) >> 1;
LL tmp = check(mid);
if (tmp) {
l = mid + 1;
rans = tmp;
}
else {
r = mid - 1;
}
}
cout << r + 1 << ' ' << rans << '\n';
}
return 0;
}

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

  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. 【Hibernate】Re07 关系映射处理

    一.单向多对一关系映射处理 演示案例列举了员工与部门的关系,一个部门下具有多个员工,相反的一个员工只隶属于一个部门下面 Maven依赖坐标: <dependency> <groupI ...

  2. 【Shiro】08 SpringBoot整合

    需要的依赖的坐标: <!-- Shiro依赖 --> <dependency> <groupId>com.github.theborakompanioni</ ...

  3. 【转载】 gym atari游戏的环境设置问题:Breakout-v0, Breakout-v4, BreakoutNoFrameskip-v4和BreakoutDeterministic-v4的区别

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

  4. 如何解决单IP爬取网站的单IP受限问题

    由于最近博导承接了一项国家科技项目,需要对大量的网站进行爬取,但是现在的很多网站都使用了反爬手段,比如限制一个session的不同网页的访问时间间隔,甚至更有甚者直接对IP地址也做了限制.对于限制se ...

  5. ubuntu22.04 终端显示数字剑雨

    数字剑雨是读大学时候常用的屏保,这些年基本也再没有用过,不经意间想到了这个曾经的屏保,发现Ubuntu原版的桌面系统是没有屏保的,又不想换桌面系统,想想还是单独安装一下这个数字剑雨吧. 在Ubuntu ...

  6. NVIDIA显卡cuda的多进程服务——MPS(Multi-Process Service)

    相关内容: tensorflow1.x--如何在C++多线程中调用同一个session会话 tensorflow1.x--如何在python多线程中调用同一个session会话 参考: https:/ ...

  7. Apache SeaTunnel 4月回顾:明星贡献者与技术突破

    各位热爱 SeaTunnel 的小伙伴们,SeaTunnel 社区 4 月份月报来啦!这里将记录 SeaTunnel 社区每月的重要更新,欢迎关注! 月度 Merge 之星 感谢以下小伙伴 4 月为 ...

  8. springcloud config坑系列一之Connection pool shut down on "zuul.host.*" property change

    在使用springcloud config自动刷新功能难免会踩到一些坑,下面来介绍下 在生成中经常需要动态刷新配置,只需要增加@RefreshScope,并且执行手动刷新链接/actuator/ref ...

  9. Linux驱动小技巧 | 利用DRIVER_ATTR实现调用内核函数

    1. 前言 很多朋友在调试驱动的时候,都会遇到这样一个场景: 修改一个参数,然后调用某个内核中的函数. 比如将某个gpio的值拉高/拉低,修改某个寄存器的值等等. 如果每一个参数都通过字符设备的ioc ...

  10. 20.从0学ARM-移植uboot支持exynos4412

    经过前面一章的学习,我们已经了解了什么是uboot,本章主要目的是如何编译和移植uboot,增加串口.网络.emmc等功能,让他支持exynos4412开发板. 一.移植步骤 1. Uboot配置 指 ...