HDU-5768 Lucky7(中国剩余定理+容斥原理)

题意

给定两个长度为 n n 的数组 A,P ,求区间 [L,R] [ L , R ] 中满足 x x 7 的倍数且对于 i[1,n] ∀ i ∈ [ 1 , n ] x≢Ai(modPi) x ≢ A i ( mod P i ) ,求 x x 的个数。
1L<R1018
1i=1nPi1018 1 ≤ ∏ i = 1 n P i ≤ 10 18 1Pi105 1 ≤ P i ≤ 10 5

思路

直接暴力肯定会超时,但是分别统计满足数对 (Ai,Pi) ( A i , P i ) 的数的个数,再直接相加会有重复,而将所有数对 CRT C R T 在一起再统计则会漏算。这时,就需要运用容斥原理。
对于这种取数类型的题目,容斥满足“偶加奇减”的原则,即取偶数个数对时相加,取奇数个数对时相减。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
typedef long long LL;
using namespace std;
LL L,R,in_ex;
int n,A[18],P[18];

struct CRT
{
    LL A,P;
    LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
    void exgcd(LL a,LL b,LL &x,LL &y)
    {
        if(!b){x=1,y=0;return;}
        exgcd(b,a%b,y,x);y-=a/b*x;
        return;
    }
    LL Exgcd(LL A,LL B,LL C)
    {
        LL k1,k2;
        exgcd(A,B,k1,k2);
        return (k1*C%B+B)%B;
    }
    void kase_insert(CRT _)
    {
        LL res=Exgcd(P,_.P,_.A-A);
        A+=P*res;
        P=P/gcd(P,_.P)*_.P;
        return;
    }
};

LL count(CRT sum,LL bnd){return (bnd-sum.A+sum.P)/sum.P;}
void dfs(int k,int cnt,CRT sum)
{
    if(k>n)
    {
        in_ex+=(cnt&1?-1:1)*(count(sum,R)-count(sum,L-1));
        return;
    }
    CRT _sum=sum;
    _sum.kase_insert((CRT){A[k],P[k]});
    dfs(k+1,cnt+1,_sum);
    dfs(k+1,cnt,sum);
    return;
}

int main()
{
    int T;
    scanf("%d",&T);
    FOR(Ti,1,T)
    {
        in_ex=0;
        scanf("%d%lld%lld",&n,&L,&R);
        FOR(i,1,n)scanf("%d%d",&P[i],&A[i]);
        dfs(1,0,(CRT){0,7});
        printf("Case #%d: %lld\n",Ti,in_ex);
    } 
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值