P10583 题解
FutureSnow · · 题解
前言
时间复杂度不是最优,但个人感觉更容易想的做法。
思路
首先不难看出题目生成的图是一个树形结构。设树有
考虑根号分治,设立阈值
然后处理编号
优化
上述做法的瓶颈在于需要
- 其子节点是且仅是编号在
[x^2, x^2 + 2x] 区间内的所有点。 - 对于任意一个编号
i \in [x^2, x^2 + 2x] 的节点,其与节点x 间的边权为i - x^2 。也就是说,编号为x 的点与其子节点间的边权为值域在[0, 2x] 间且公差为1 的等差数列。
对于第
考虑分块,设块长为
不难发现取
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1000000, mod = 998244353, L = (1 << 16);
int n, S, val[N + 10], sq[N + 10], f[4 * N + 10], A[4 * N + 10], B[4 * N + 10], C[4 * N + 10], d[N + 10];
inline int x2(int x){
return x * x;
}
inline int ksm(int u, int v){
int mul = 1;
while(v){
if(v & 1) mul = mul * u % mod;
u = u * u % mod, v >>= 1;
}
return mul;
}
inline void fwt(int *f, int len, int opt){
for(int i = 1; i < len; i <<= 1)
for(int j = 0; j < len; j += (i << 1))
for(int k = 0; k < i; k++){
int x = f[j + k], y = f[i + j + k];
f[j + k] = x + y, f[i + j + k] = x - y;
if(!opt) f[j + k] >>= 1, f[i + j + k] >>= 1;
}
}
int dfs(int x){
if(x == 1 || val[x]) return val[x];
return val[x] = (dfs(sq[x]) ^ (x - x2(sq[x])));
}
signed main (){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n;
S = sqrt(n);
for(int i = 1; x2(i) <= N; i++) sq[x2(i)] = i;
for(int i = 1; i <= N; i++){
if(!sq[i])
sq[i] = sq[i - 1];
val[i] = dfs(i);
}
if(n <= N) for(int i = 1; i <= n; i++) f[val[i]]++;
else{
for(int i = 1; i <= N; i++) f[val[i]]++;
int sq = 1000, pos = sq, len = 2000, ls = 1, lst = sq, Max = 0;
for(int i = sq; x2(i) <= n; i++){
d[i] = x2(i + 1) - x2(i);
A[val[i]]++;
pos = i;
}
A[val[pos]]--;
Max = d[pos - 1];
for(int i = len; i < Max; i += len, ls += len){
for(int j = ls; j <= i; j++) B[j] = 1;
fwt(A, L, 1);
fwt(B, L, 1);
for(int j = 0; j < (L); j++) C[j] = A[j] * B[j];
fwt(A, L, 0);
fwt(B, L, 0);
fwt(C, L, 0);
for(int j = 0; j < (L); j++) f[j] += C[j];
for(int j = ls; j <= i; j++) B[j] = 0;
for(int j = lst; j < pos; j++)
if(d[j] <= i + len){
A[val[j]]--;
lst = j + 1;
}
if(i + len >= Max) break;
}
int sum = N - 1;
for(int i = sq; i < pos; i++){
int P = d[i] / len;
sum += d[i];
for(int j = P * len + 1; j < d[i]; j++)
f[val[i] ^ j]++;
}
for(int i = sq + 1; i < pos; i++) f[val[i] ^ 0]++;
for(int i = 0; i <= d[pos] && sum < n; i++, sum++) f[val[pos] ^ i]++;
}
fwt(f, L, 1);
for(int i = 0; i < L; i++) f[i] = x2(f[i]);
fwt(f, L, 0);
int ans = 1;
for(int i = 1; i < L; i++) ans = ans * ksm(i, f[i] >> 1) % mod;
cout << ans << '\n';
return 0;
}