P9994 [Ynoi Easy Round 2024] TEST_132 题解
题解怎么都是用暴力日过去的啊。
思路#
考虑根号分治,设阈值为
对于第二维出现次数超过
对于第二维出现次数小于
大多数题解对出现次数小于
对于所有的数,我们把他们的离散对数算出来,在模
那么我们可以预处理
而在修改时,对原数平方相当于对离散对数乘二。
同样可以预处理二的次幂来做到。
问题就变成了在最开始计算每个数的离散对数。
首先可以使用 BSGS,我们预处理前
这样在复杂度上就已经非常优越了。
但在实现上,由于 BSGS 与哈希表(即使是手写哈希表)常数过大。
所以跑
甚至表现的结果不如快速幂(当然这也与数据有关)。
怎么办呢。
考虑一种 BSGS 次数更少的方法。
对
于是可以得到:
若我们已经预处理出
此时
于是,我们可以根据上面两条式子,将计算
由于
我们也只需要执行
这样常数大大减少,就可以完全不卡常的过了。
所以正解怎么可能会卡常呢。
Code#
阈值
这是完全没卡常的代码,在总时间可能没有快速幂快。
但最慢点只要
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
#define eb(...) emplace_back(__VA_ARGS__)
#define fro(i, x, y) for(int i = (x);i <= (y);i++)
#define pre(i, x, y) for(int i = (x);i >= (y);i--)
typedef int64_t i64;
typedef pair<int, int> PII;
const int B = 500;
const int D = 5e6;
const int P = 4e4;
const int I = 131072;
const int M = 2935019;
const int N = 1e6 + 10;
const int G = 5e6 + 10;
const int mod = 1e9 + 7;
const int phi = 1e9 + 6;
const int lgf = 5e8 + 3;
int n, m;
int sum[N], tag[N], ton[N];
int a[N], b[N], v[N], g[N], d[N];
vector<PII> big[N], sml[N];
i64 inv, pw1[N], pw2[N], pw3[N];
struct HashMap
{
int cnt, head[M];
struct edge { int to, val, nxt; } e[G];
inline int &operator[](const int &tmp)
{
int x = tmp % M;
for(int i = head[x]; i; i = e[i].nxt)
if(e[i].to == tmp) return e[i].val;
e[++cnt] = {tmp, 0, head[x]}, head[x] = cnt;
return e[cnt].val;
}
inline bool find(const int &tmp)
{
int x = tmp % M;
for(int i = head[x]; i; i = e[i].nxt)
if(e[i].to == tmp) return 1;
return 0;
}
} mp;
inline i64 power(int x)
{ return pw1[x&(I-1)] * pw2[x>>17] % mod; }
inline i64 power(i64 x, i64 y)
{
i64 res = 1;
while(y)
{
if(y & 1) res = res * x % mod;
x = x * x % mod, y /= 2;
}
return res;
}
inline void init()
{
pw1[0] = pw2[0] = pw3[0] = 1; i64 pw = 1;
fro(i, 1, I) pw1[i] = pw1[i - 1] * 5 % mod;
fro(i, 1, I) pw2[i] = pw2[i - 1] * pw1[I] % mod;
fro(i, 1, N - 10) pw3[i] = pw3[i - 1] * 2 % phi;
fro(i, 0, D) mp[pw] = i, pw = pw * 5 % mod;
inv = power(power(D), mod - 2);
auto ask = [&](int x) {
fro(i, 0, 200)
{
if(mp.find(x))
return i * D + mp[x];
x = x * inv % mod;
}
return -1;
};
fro(i, 1, P) d[i] = (i % 5 == 0 ? d[i / 5] + 1 : ask(i));
}
inline void add(int &x, int y, int M = mod)
{ x = (x + y >= M ? x + y - M : x + y); }
inline int Add(int x, int y)
{ return (x + y >= phi ? x + y - phi : x + y); }
inline int ask(int x)
{
if(x <= P) return d[x];
int q = mod / x, r = mod % x;
if(r < x - r)
return Add(Add(lgf, ask(r)), phi - d[q]);
return Add(ask(x - r), phi - d[q + 1]);
}
inline void solve()
{
cin >> n >> m, init();
fro(i, 1, n) cin >> a[i] >> b[i] >> v[i];
fro(i, 1, n) g[i] = ask(v[i]);
fro(i, 1, n) ton[b[i]]++;
fro(i, 1, n)
{
if(ton[b[i]] <= B) sml[b[i]].eb(a[i], g[i]);
if(ton[b[i]] > B) big[a[i]].eb(b[i], v[i]), add(sum[b[i]], v[i]);
}
fro(i, 1, m)
{
int op, x;
cin >> op >> x;
if(op == 1)
{
for(auto &[a, b] : big[x])
{
add(sum[a], mod - b);
b = 1ll * b * b % mod;
add(sum[a], b);
}
tag[x]++;
}
else
{
if(ton[x] > B)
cout << sum[x] << "\n";
else
{
int res = 0;
for(auto [a, b] : sml[x])
{
int pos = b * pw3[tag[a]] % phi;
add(res, power(pos));
}
cout << res << "\n";
}
}
}
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
solve();
return 0;
}
作者:JiaY19
出处:https://www.cnblogs.com/JiaY19/p/17935161.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)