P7451 [THUSCH2017] 杜老师

P7451 [THUSCH2017] 杜老师

思路

注意到完全平方数在质因数分解之后所有质数的指数都是偶数,既然只关心奇偶性,我们在 \(\bmod 2\) 意义下考虑这个问题,而如果将两个数乘在一起,它们的指数相加,在 \(\bmod 2\) 意义下等价于异或指数,指数看作二进制数,如果我们得到了 \(l\sim r\) 的异或线性基,这就是一个线性基的经典问题了。

如果对区间每个数暴力分解质因数之后插入线性基,这样的复杂度是 \(O((r - l)(\sqrt V + \pi^2(V)))\),如果套一个 bitset 可以获得 \(\dfrac 1\omega\) 的优秀常数。

熟知一个数 \(x\) 最多只有一个因数大于 \(\sqrt x\),直接开值域个线性基相当浪费,所以把这些大因数单独开一个 unordered_map 存起来就好了,这样的复杂度是 \(O(\dfrac{1}{\omega}(r - l)(\sqrt V + \pi^2(\sqrt V)))\) 的。

需要优化,通过观察题解,发现了这个结论:

如果区间长度大于 \(2\sqrt V\) 左右,每一个在区间内出现的质因子都会被插入线性基。

有了这个,对于长度大于 \(2\sqrt V\) 的就查质因子,对于长度不大于 \(2\sqrt V\) 的就用上一个方法做。

代码比较好写。

// Problem: P7451 [THUSCH2017] 杜老师
// Author: Moyou
// Copyright (c) 2024 Moyou All rights reserved.
// Date: 2024-01-29 18:40:17

#include <iostream>
#include <bitset>
#include <unordered_map>
using namespace std;
const int N = 1e7 + 10, mod = 998244353, B = 6500, M = 460; // magic number

int l, r, primes[N], tot;
bool st[N];
void sieve() {
    for(int i = 2; i < N; i ++) {
        if(!st[i]) primes[++ tot] = i;
        for(int j = 1; j <= tot && primes[j] * i < N; j ++) {
            st[i * primes[j]] = 1;
            if(i % primes[j] == 0) break;
        }
    }
}
bitset<M> ba[M], tmp;
unordered_map<int, bitset<M> > big;
int bsiz;
int qmi(int a, int b) {
    int res = 1;
    while(b) {
        if(b & 1) res = 1ll * res * a % mod;
        b >>= 1, a = 1ll * a * a % mod; 
    }
    return res;
}
void work() {
    cin >> l >> r;
    if(r - l + 1 >= B) {
        int cnt = 0;
        for(int i = 1; i <= tot && primes[i] <= r; i ++) {
            if(r / primes[i] != (l - 1) / primes[i])
                cnt ++;
        }
        cout << qmi(2, r - l + 1 - cnt) << '\n';
    }
    else {
        bsiz = 0;
        big.clear();
        for(int i = 0; i < M; i ++) ba[i].reset();
        for(int i = l, t; i <= r; i ++) {
            t = i, tmp.reset();
            for(int j = 1; j <= tot && t > 1 && primes[j] * primes[j] < N; j ++)
                while(t % primes[j] == 0) t /= primes[j], tmp[j - 1] = 1 ^ tmp[j - 1];
            if(t > 1) {
                if(!big.count(t)) {
                    bsiz ++, big[t] = tmp;
                    goto ne; // goto 谁用谁爽
                }
                tmp ^= big[t];
            }
            for(int i = M - 1; ~i; i --)
                if(tmp[i]) {
                    if(!ba[i].any()) {
                        bsiz ++, ba[i] = tmp;
                        break;
                    }
                    tmp ^= ba[i];
                }
            ne:;
        }
        cout << qmi(2, r - l + 1 - bsiz) << '\n';
    }
    return ;
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    sieve();
    while (T--) work();

    return 0;
}

posted @ 2024-01-29 23:21  MoyouSayuki  阅读(6)  评论(0编辑  收藏  举报
:name :name