ABC339

1|0基本情况

ABC秒了,D读错题卡了一段时间,还好爆搜强项,E感觉极其类似LIS,但是似乎又不能用二分DP来写。

2|0E

https://atcoder.jp/contests/abc339/tasks/abc339_e

线段树优化DP

事实如此,确实类似LIS,但是通过线段树来维护区间最大值.

暂时还没有熟练线段树,先用atc的库来平替.

实现上就是将元素依次加入线段树 , 然后用当前元素符合条件区间的最大值来更新当前元素对应点的值.

最后输出总区间最大值即可.

换言之,对于当前的 dpi,只能从dpj(j<i\and|aiaj|k) 中找最大。

所以对线段树中对应的 ai 这个点更新最大步数,然后转移时找数值在 [aid,ai+d] 中对应的DP最大值就好。

int op(int a, int b) { return max(a, b); } int e() { return 0; } const int A = 500010; int main() { int n, d; cin >> n >> d; atcoder::segtree<int, op, e> seg(A); for (int i = 0, x; i < n; i++) { cin >> x; int l = max(0, x - d); int r = min(A - 1, x + d); int MAX = seg.prod(l, r + 1); seg.set(x, MAX + 1); } cout << seg.all_prod() << endl; return 0; }

3|0F - Product Equality

https://atcoder.jp/contests/abc339/tasks/abc339_f

哈希人类智慧

怎么验证三个极大数 Ai×Aj=Ak

直接类比哈希,找几个模数作同余,只要在所有模数意义下相等那就可以认为是相等。

一开始还卡在两个大的数要怎么进行乘法,想到从数位上考虑去了。

事实上可以直接在输入时取模,比如 14432 其实就是 1×104+4×103+4×102+3×101+2×100

因此在输入一个极大数的时候就可以边乘底数边取模,然后构造同余意义下的较小数。

换一种角度,实际上就是把数字当成字符串了,每个数位是字符串的字符,那么处理就是很自然的了。

在同余意义下进行相乘验证即可。

constexpr int B = 3; int mod[]{1000000007, 1000000009, 998244353}; int base[]{10, 10, 10}; struct String { std::vector<i64> hash[B]; std::string s; String(){} String(std::string s_) : s(s_) { for (int i = 0; i < B; i++) { hash[i].push_back(0); for (auto& ch : s) { hash[i].push_back((hash[i].back() * base[i] + (ch - '0')) % mod[i]);//其实就是正常的哈希处理 } } } friend std::istream &operator>>(std::istream &is, String& str) { is >> str.s; str = String(str.s); return is; } std::array<i64, B> get() {std::array<i64, B> res{}; for (int i = 0; i < B; i++) {res[i] = hash[i].back();} return res;} }; std::array<i64, B> multiply(String& a, String& b) { std::array<i64, B> res{}; for (int i = 0; i < B; i++) {res[i] = a.hash[i].back() * b.hash[i].back() % mod[i];} return res; } signed main() { std::cin.tie(nullptr)->sync_with_stdio(false); int n; std::cin >> n; std::map<std::array<i64, B>, int> cnt; std::vector<String> s(n); for (i64 i = 0; i < n; i++) { std::cin >> s[i]; cnt[s[i].get()] += 1; } i64 ans = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { std::array<i64, B> mul = multiply(s[i], s[j]); ans += cnt[mul]; } } std::cout << ans << '\n'; return 0; }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/18005356.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示