(中国剩余定理模版)hdoj 5768 Lucky7

  解(1<<(n+1))-1个同余方程组,然后容斥。作为中国剩余定理的模版。另外数据范围刚好超出long long,用了__int128。

#include <iostream>    
#include <stdio.h>    
#include <cmath>    
#include <algorithm>    
#include <string>  
#include <string.h>       
#include <vector>    
#include <queue>    
#include <stack>
#include <map>
#include <sstream>

using namespace std;

#define ll __int128

void extend_Euclid(ll a, ll b, ll &x, ll &y){
    if(b == 0){
        x = 1;
        y = 0;
        return;
    }
    extend_Euclid(b, a % b, x, y);  
    ll tmp = x;  
    x = y;  
    y = tmp - (a / b) * y;  
}  

ll CRT(ll a[],ll m[],ll n){
    ll M = 1;  
    ll ans = 0;  
    for(int i=0; i<n; i++)  
        M *= m[i];
    for(int i=0; i<n; i++){
        ll x, y;  
        ll Mi = M / m[i];  
        extend_Euclid(Mi, m[i], x, y);  
        ans = (ans + Mi * x * a[i]) % M;  
    }  
    if(ans < 0) ans += M;  
    return ans;  
}

ll p[20];
ll a[20];

ll read(){
    long long res = 0;
    cin>>res;
    return res;
} 

int main(){
    int t;
    cin>>t;
    int cas = 0;
    while(t--){
        cas++;

        ll n,l,r;
        n = read();
        l = read();
        r = read();

        for(int i=0;i<n;i++){
            p[i] = read();
            a[i] = read();
        }

        int End = 1<<n;
        ll ans = 0;
        for(int k=0;k<End;k++){
            int bc = __builtin_popcount(k);

            ll mm[20];
            ll aa[20];
            int sz = 0;
            ll lcm = 7;
            for(int i=0;i<n;i++){
                if(k&(1<<i)){
                    mm[sz] = p[i];
                    aa[sz] = a[i];
                    lcm *= p[i];
                    sz++;
                }
            }
            mm[sz] = 7;
            aa[sz] = 0;
            sz++;

            ll crt = CRT(aa,mm,sz);
            ll la = l/lcm;
            ll ra = r/lcm;
            ll tmp = ra - la;
            if((l%lcm)<=crt && (r%lcm)>=crt){
                tmp++;
            }
            if((l%lcm)>crt && (r%lcm)<crt){
                tmp--;
            }

            if(bc&1){
                ans -= tmp;
            }else{
                ans += tmp;
            }
        }

        printf("Case #%d: ",cas);
        long long ANS = ans;
        cout<<ANS<<endl;
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值