HDU 5768 Lucky7

题意:

给定0<L<R<1018,给定N≤15个非法条件
即x%pi=ai,ai<pi105,∏pi1018
求[L, R]区间内能被7整除,且合法的数字的个数

分析: 容斥 加 CRT

非法条件有15个,显然的容斥一下,对于每个条件我们可以用CRT算出个数
但是这里有被7整除的条件,不如把这个条件当作强制条件
之后把全集变成模7域下的全集,即[L, R]整除7的数的个数tot
最后ans=tot−容斥的结果
时间复杂度O(n×2n×nlogC)
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = a; i < b; i++)
const int N = 1e5 + 10;
typedef long long LL;
LL exgcd(LL a, LL b, LL& x, LL& y) {
    LL g = a;
    if(!b) x = 1, y = 0;
    else {
        g = exgcd(b, a % b, y, x);
        y -= a / b * x;
    }
    return g;
}

int n;
LL x, y;
int r[N], p[N];

LL a[N], b[N], m[N];
pair<LL, LL> excrt(int n, LL* a, LL* b, LL* m) { //(a * x) % m 同于 b
    LL B = 0, M = 1;
    for(int i = 1; i <= n; ++i) {
        LL A = (M * a[i]) % m[i], c = (b[i] - B * a[i]) % m[i];
        LL x, y, g = exgcd(A, m[i], x, y);
        if(c % g) return { -1, -1};
        x = c / g * x % (m[i] / g);
        B += x * M;
        M *= m[i] / g;
        B %= M;
    }
    B = (B + M) % M;
    if(!B) B = M;
    return {B, M};
}
LL cal(LL x, LL B, LL M){
    LL ret = x >= B;
    ret += (x - B) / M;
    return ret;
}
int main()
{
    int T, ks = 0;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%I64d%I64d", &n, &x, &y);
        rep(i, 0, n) scanf("%I64d%I64d", &p[i], &r[i]);
        LL ans1 = 0, ans2 = 0;
        rep(s, 1, 1<<n){
            int id = 0;
            rep(i, 0, n){
                if(s >> i & 1){
                    ++id;
                    a[id] = 1;
                    m[id] = p[i];
                    b[id] = r[i];
                }
            }
            ++id;
            a[id] = 1; m[id] = 7; b[id] = 0;
            auto ret = excrt(id, a, b, m);
            LL B, M;
            tie(B, M)  = ret;
            LL tmp = cal(y, B, M) - cal(x - 1, B, M);
            if((id - 1) & 1) ans2 += tmp;
            else ans2 -= tmp;
        }
        ans1 = (y / 7) - (x - 1) / 7 - ans2;
        printf("Case #%d: %I64d\n", ++ks, ans1);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值