HDU 5768 Lucky7

来源:互联网 发布:dm500刷机软件 编辑:程序博客网 时间:2024/06/08 18:42

题意:

给定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 0
原创粉丝点击