jzoj5836 Sequence (区间筛)

31 篇文章 0 订阅

题意

求[L,R]中,最小质因子大于K的数(包括素数)的异或和。
L,R<=1e14,K<=1e9
R-L<=1e7

就TM是个线筛

在线筛过程中,由于每个数N都会被他的最小质因子筛到。若不是质数,则其最小质因子必定 <=N <= N <script type="math/tex" id="MathJax-Element-141"><=\sqrt N</script>。

注意到当枚举的数>= N N 时,我们就可以将 N N <script type="math/tex" id="MathJax-Element-143">N</script>以内的合数全部标记出来了。

那么,我们线筛做到1e7的时候,[L,R]区间里的数如果被标记了(注意当i<=K时才标记),那说明其有K以内的质因子。
若没有被标记,则要么他是素数,要么是应该在[K+1,1e7]这一段区间里标记的数,也就是应该算进答案的数。

这题就没了。

实现

里面混了个没用的pollard rho,脑抽的时候打的。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <ctime>
#define abs(x) ((x) > 0 ? (x) : -(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const int D = 1e7;
ll L,R,K;
ll ans;
ll p[700000], is[D + 10], ali[10000000 + 10];
ull seed = 998244353;
ull rnd() {
    return rand() + rand() * RAND_MAX;
    return seed = seed * 1000000007 ^ 233333333;
}

ll mul(ll x, ll y,ll mo) {
    x%=mo,y%=mo;
    ll z=(ld) x * y / mo;
    z = x * y - z * mo;
    if(z < 0) z += mo; else if(z > mo) z -= mo;
    return z;
}

void init() {
    for (int i = 2; i <= D; i ++) {
        if (is[i] == 0) {
            p[++p[0]] = i;
            if (i <= K) {
                ll st = L + i - L % i;
                if (st - i >= L) st -= i;
                if (st == i) st += i;
                for (; st <= R; st += i)  {
                    ali[st - L] = 1;
                }
            }
        }
        for (int j = 1; j <= p[0] && i * p[j] <= D; j++) {
            is[i * p[j]] = 1;
            if (i % p[j] == 0) break;
        }
    }
}

ll ksm(ll x,ll y,ll mo) {
    ll ret = 1;
    for (; y; y>>=1) {
        if (y & 1) ret = mul(ret, x, mo);
        x = mul(x, x, mo);
    }
    return ret;
}

ll f[100];
int mr(ull a,ll p) {
    a%=p; if (a==0) return 1;
    ll d = p - 1;
    while ((d&1)==0) d>>=1;
    ll x = ksm(a, d, p);
    while (d < p - 1) {
        ll nx = mul(x, x, p);
        if (nx == 1) {
            if (x != 1 && x != p - 1) return 0;
            return 1;
        }
        x = nx; d *= 2;
    }
    return x == 1;
}

ll gcd(ll x,ll y) {
    return y==0?x:gcd(y,x%y);
}

#define nex(x) (((x) * (x) + c) % a)
ll stop=0;
void pr(ll a) {
    if (stop) return;
    if (mr(2,a) && mr(3,a) && mr(61,a)) {
        if (a < K) stop = 1;
        f[++f[0]] = a;
        return;
    }

    while (1) {
        ll c = rnd() % a + 1;
        ll x = c, y = nex(x);
        while (x != y) {
            ll g = gcd(abs(x - y), a);
            if (g != a && g != 1) {
                pr(a / g);
                pr(g);
                return;
            }
            x = nex(x), y = nex(nex(y));
        }
    }
}

int cnt;
int check(ll x) {
    if (x <= D && is[x] == 0) return 1;
    f[0] = 0; stop=0;
    pr(x);
    cnt++;
    if (f[1]==x) return 1;
    ll mi = 1e18;
    for (int i = 1; i <= f[0]; i++)
        mi = min(mi, f[i]);
    if (mi > K) return 1; else return 0;
}

int main() {
    freopen("prime.in","r",stdin);
//  freopen("prime.out","w",stdout);
    cin>>L>>R>>K;
    init();
    for (ll i = L; i <= R; i ++) 
        if (!ali[i - L]) {
            ans ^= i;
        }
    cout<<ans<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值