ABC339
基本情况
ABC秒了,D读错题卡了一段时间,还好爆搜强项,E感觉极其类似LIS,但是似乎又不能用二分DP来写。
E
https://atcoder.jp/contests/abc339/tasks/abc339_e
线段树优化DP
事实如此,确实类似LIS,但是通过线段树来维护区间最大值.
暂时还没有熟练线段树,先用atc的库来平替.
实现上就是将元素依次加入线段树 , 然后用当前元素符合条件区间的最大值来更新当前元素对应点的值.
最后输出总区间最大值即可.
换言之,对于当前的 \(dp_i\),只能从\(dp_j(j < i \and \left | a_i - a_j \right | \leq k)\) 中找最大。
所以对线段树中对应的 \(a_i\) 这个点更新最大步数,然后转移时找数值在 \([a_i - d, a_i + 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;
}
F - Product Equality
https://atcoder.jp/contests/abc339/tasks/abc339_f
哈希人类智慧
怎么验证三个极大数 \(A_i\times A_j = A_k\) ?
直接类比哈希,找几个模数作同余,只要在所有模数意义下相等那就可以认为是相等。
一开始还卡在两个大的数要怎么进行乘法,想到从数位上考虑去了。
事实上可以直接在输入时取模,比如 \(14432\) 其实就是 \(1\times 10^4 + 4\times10^3 + 4\times 10^2 + 3\times10^1 + 2\times10^0\)。
因此在输入一个极大数的时候就可以边乘底数边取模,然后构造同余意义下的较小数。
换一种角度,实际上就是把数字当成字符串了,每个数位是字符串的字符,那么处理就是很自然的了。
在同余意义下进行相乘验证即可。
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;
}