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

32 篇文章 0 订阅

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5768

题意:求[a,b]区间内能被7整除且不满足x%pi=ai(1<=i<=n)的数有多少个;

题解:


因为满足任意一组pi和ai,即可使一个“幸运数”被“污染”,我们可以想到通过容斥来处理这个问题。当我们选定了一系列pi和ai后,题意转化为求[x,y]中被7整除余0,且被这一系列pi除余ai的数的个数,可以看成若干个同余方程联立成的一次同余方程组。然后我们就可以很自然而然的想到了中国剩余定理。需要注意的是,在处理中国剩余定理的过程中,可能会发生超出LongLong的情况,需要写个类似于快速幂的快速乘法来处理。


#include <bits/stdc++.h>
using namespace std;
//#define mod 1000000007
long long quick_mul(long long a, long long b,long long mod)
{
    long long ans=0;
    while(b)
    {
        if(b&1)ans=(ans+a)%mod;
        b>>=1;
        a=(a+a)%mod;
    }
    return ans;
}
long long extend_Euclid(long long a, long long b, long long &x, long long &y)
{
    if(b==0){x = 1;y = 0;return a;}
    long long r = extend_Euclid(b, a%b, y, x);
    y -= a/b*x;
    return r;
}
#define bug cout<<"bug"<<endl
#define INF 0x3f3f3f3f
const int MAXN = 107;
long long mo[MAXN],er[MAXN];
int vis[MAXN];
long long China(int n)
{
    long long M = 1, ans = 0;
    for (int i = 0; i <= n; ++i)if(vis[i])
        M *= mo[i];
    for(int i = 0; i <= n; i++)if(vis[i])
    {
        long long N = M/mo[i];
        long long x, y;
        extend_Euclid(N, mo[i], x, y);
        x = (x%mo[i]+mo[i])%mo[i];
        ans = ((ans+quick_mul(quick_mul(er[i],N,M), x, M))%M + M) % M;
    }
    return ans;
}
int main()
{
    int T,n,cas=1;;
    long long a,b;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%I64d%I64d",&n,&a,&b);
        for(int i=0; i<n; ++i)
            scanf("%I64d%I64d",&mo[i],&er[i]);
        mo[n]=7,er[n]=0;
        vis[n]=1;
        long long l7=7;
        long long ans=0;
        int temp=1<<n;
        for(int i=0; i<temp; ++i)
        {
            int k=i,flag=0;
            long long all=7,poi;
            for(int j=0; j<n; ++j)
            {
                vis[j]=k&1;
                k>>=1;
                flag+=vis[j];
                if(vis[j])all*=mo[j];
            }
            long long c=China(n);
            if(c>a)c-=((c-a)/all)*all;
            if(c<a)c+=((a-c)/all)*all;
            if(c<a)c+=all;
            if(c<=b)poi=(b-c)/all+1;
            else poi=0;
            if(flag&1)ans-=poi;
            else ans+=poi;
        }
        printf("Case #%d: %I64d\n",cas++,ans);
    }
}

/*
4
2 1 100
3 2
5 3
0 1 100
0 1 1
0 7 7
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值