hdu 5768 Lucky7 容斥原理 中国剩余定理

题目传送门:点击打开链接

题意:给你区间[a,b],在这区间里 找出 既是7的倍数 x,并且 x%pi!=ai的个数 有多少?

思路:看到这题  跟模有关系  大概跟 中国剩余定理有关,可是题目说的 只要 符合 x%pi=ai一项 就不能算个数,所以只是中国剩余定理 不可行的,那么我们只有一个一个 求出个数,然后再用7的倍数的个数-求出的个数,可是 一个一个求这会有重复的,所以我们 就要用到容斥。。 如果在容斥的过程中用普通互素的中国剩余定理的方法 那就要注意在解的时候会出现 爆long long的情况,当然 我们也可以避免这种情况,第一种用快速乘法。那么 第二种方法可以正常解,并且不会爆long long .

第二种:解释: 我们在第一种的方法  是 列 方程  x=ai mod pi,再运用中国剩余定理,而我们现在  利用7的倍数这个条件 列出 7x= ai mod pi    然后对他化简  x= ci mod pi  注意这里的x 符合条件  a<=7x<=b   即  在[a,b]符合 7的倍数    可以写成  7*p,7*(p+1),7*(p+2),7*(p+3).......,那么这里的x=p,p+1,p+2,p+3....   所以区间我们可以变成 [a/7,b/7]  所以接下来的思路和第一种一样 运用容斥和普通的互素的中国剩余定理 就可以解决 这个爆long long 的问题。(其实 就是 M比第一种的M少乘个7)

当然 如果你用不互素的中国剩余定理的模版  应该也不会出现 long long 的问题。在这里那代码我就只是贴 普通互素中国剩余定理 的二种情况的代码了,最后一个就不贴了。

第二种:

#include <iostream>
#include <cstring>
#define rep(i,o,u) for(int i=(int)(o);i<=(int)(u);++i)
#define clr(a,x) memset(a,(x),sizeof(a))
using namespace std;
typedef long long ll;
ll n,x,y;
ll a[20],b[20];int cnt=0;
void ex_gcd(ll aa,ll bb,ll &xx,ll &yy)
{
    if(!bb)
    {
        xx=1,yy=0;
        return;
    }
    ll x1,y1;
    ex_gcd(bb,aa%bb,x1,y1);
    xx=y1,yy=x1-(aa/bb)*y1;
}
void solve()
{
    cin>>n>>x>>y;
    rep(i,0,n-1)
    {
        cin>>a[i]>>b[i];
        for(ll j=0;;++j)                 //化简 式子
            if((b[i]+j*a[i])%7==0)
            {
                b[i]=((b[i]+j*a[i])/7)%a[i];
                break;
            }
    }
    int e=1<<n;ll ans=0;
    rep(i,1,e-1)
    {
        int nn=0;ll M=1,aa=0;
        int data[16];
        rep(j,0,n-1)
        {
            if((1<<j)>i)
                break;
            if((1<<j)&i)
            {
                data[nn++]=j;
                M*=a[j];
            }
        }
        rep(j,0,nn-1)
        {
            ll xx,yy,m=M/a[data[j]];
            ex_gcd(m,a[data[j]],xx,yy);
            aa=((aa+((xx*m)%M)*b[data[j]])%M+M)%M;
        }
        ll tt=0;
        tt+=(y/7-aa)/M;
        tt-=((x-1)/7-aa)/M;
        if(aa>(x-1)/7&&aa<=y/7)
            ++tt;
        if(nn&1)
            ans+=tt;
        else
            ans-=tt;
    }
    ans=(y/7-(x-1)/7)-ans;
    cout<<"Case #"<<++cnt<<": ";
    cout<<ans<<endl;
}
int main(int argc, const char * argv[])
{
    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
    return 0;
}

第一种:

#include <iostream>
#include <cmath>
#define rep(i,o,u) for(int i=o;i<=u;++i)
using namespace std;
typedef long long  ll;
ll pi[16],ai[16];
ll x,y;int cnt=0;
void ex_gcd(ll a,ll b,ll &xx,ll &yy)
{
    if(!b)
    {
        xx=1,yy=0;
        return;
    }
    ll x1,y1;
    ex_gcd(b,a%b,x1,y1);
    xx=y1,yy=x1-(a/b)*y1;
}
ll quickmul(ll a,ll b,ll mod)
{
    ll ans=0;
    a%=mod;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%mod;
        b>>=1;
        a=(a+a)%mod;
    }
    return ans;
}
void solve()
{
    ll ans=0;
    int n;ll M;
    cin>>n>>x>>y;
    pi[n]=7,ai[n]=0;
    ans=y/7-(x-1)/7;
    rep(i,0,n-1)
        cin>>pi[i]>>ai[i];
    int e=1<<(n);
    rep(i,1,e-1)
    {
        M=1;int nn=0;
        ll data[16];
        ll xx=1,yy=1;
        rep(j,0,n)
        {
            if((1<<j)>i)
                break;
            if((1<<j)&i)
            {
                data[nn++]=j;
                M*=pi[j];
            }
        }
        data[nn++]=n;
        M*=7;
        ll aa=0;
        rep(j,0,nn-1)
        {
            ll m=M/pi[data[j]];
            ex_gcd(m,pi[data[j]],xx,yy);
            aa=(aa+quickmul(quickmul(xx,m,M),ai[data[j]],M))%M;
        }
        if(aa<0)
            aa+=M;
        ll t=0;
        t=(y-aa)/M-(x-aa-1)/M;
        if(aa>=x&&aa<=y)
            ++t;
        if(nn&1)
            ans+=t;
        else
            ans-=t;
       // cout<<aa<<" "<<M<<": ";
       // cout<<t<<endl;
    }
    cout<<"Case #"<<++cnt<<": "<<ans<<endl;
}
int main(int argc, const char * argv[])
{
    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
    return 0;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值