『HDU 5768』Lucky7 中国剩余定理

转载声明:http://blog.csdn.net/acdreamers/article/details/8050018 (模板)

题意:给你一段区间的,要求能被7整除的个数,然后给你n个条件, 其中的得到所有数不能满足 给出的 x%x1=r1, x%x2=r2。。。等条件.输出个数.

个人感想:
这是一道中国剩余定理题目, 我当时比赛的时候我也不会做…我只是知道有这样的公式…就是可以求出满足的所有解,但我不知道是什么鬼…然后大牛告诉我了是中国剩余定理.我特么就半桶水的东西,我感觉怎么也不会考…然后之前都没学下去,真是瞎鸡巴搞了. 我是知道要用到容斥,算了…不说心酸史, 我直接套上链接的模板去做的,在统计区间中整数的数组的时候要注意 最左区间要-1, 和求那个前缀和一样,否则就除问题了,我坑了一个多小时在那.默哀… 例如 求 7<= 7t<=9;满足的条件中 t的个数, 这时候答案是0的! 因为是向下取整导致这样的问题,所以求t时 应该 7-1<7t<=9 这样才求出来是1! 而且要注意 t能满足0的情况,这样的区间相减是不包括0的!!

/* Author:GavinjouElephant
 * Title:
 * Number:
 * main meanning:
 *
 *
 *
 */

//#define OUT
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define Clear(x) memset(x,0,sizeof(x))
const int INF=0x3f3f3f3f;
typedef long long LL;
const int maxn=20;
LL n,x,y;
int T;
LL a[maxn],p[maxn];
LL gcd(LL a,LL b)
{
    return b? gcd(b, a % b) : a;
}

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 Inv(LL a, LL b)
{
    LL d = gcd(a, b);
    if(d != 1) return -1;
    LL x, y;
    extend_Euclid(a, b, x, y);
    return (x % b + b) % b;
}

bool Merge(LL a1, LL m1, LL a2, LL m2, LL &a3, LL &m3)
{
    LL d = gcd(m1, m2);
    LL c = a2 - a1;
    if(c % d) return false;
    c = (c % m2 + m2) % m2;
    m1 /= d;
    m2 /= d;
    c /= d;
    c *= Inv(m1, m2);
    c %= m2;
    c *= m1 * d;
    c += a1;
    m3 = m1 * m2 * d;
    a3 = (c % m3 + m3) % m3;
    return true;
}
LL solve(int n)
{
    LL a1 = 0;
    LL m1 = 7;
    int tmp=0;

    while(n)
    {
        if(n&1)
        {
            LL a2 = a[tmp];
            LL m2 = p[tmp];
            LL m3, a3;
            if(!Merge(a1, m1, a2, m2, a3, m3))
                return -1;
            a1 = a3;
            m1 = m3;
        }
        tmp++;
        n>>=1;
    }

    a1=(a1 % m1 + m1) % m1;
    LL res=0;

    res+=((y-a1)/m1 -(x-a1-1)/m1);

    if(a1>=x&&a1<=y)res++;//至于为什么要特殊判断 主要我们求出来的时候是( x<=a1+mt<=y,那么两边互相消去之后的t的个数是不包括0的,所以要特判一下.

    return res;

}
LL getT(int n)
{
    int res=0;
    while(n)
    {
        if(n&1)res++;
        n>>=1;
    }
    return res;
}
LL f(LL x)
{
    if(x%2)return 1;
    return -1;
}
int main()
{
#ifdef OUT
    freopen("coco.txt","r",stdin);
    freopen("lala.txt","w",stdout);
#endif
    scanf("%d",&T);
    for(int cas=1; cas<=T; cas++)
    {
        scanf("%I64d%I64d%I64d",&n,&x,&y);
        LL ans=(y/7-(x-1)/7);

        for(int i=0; i<n; i++)
        {
            scanf("%I64d%I64d",&p[i],&a[i]);
        }
        LL tmp=0;
        LL limited=1<<n;

        for(int i=1; i<limited; i++)
        {
            int tot=getT(i);

            LL t=solve(i);
            tmp+=f(tot)*t;
        }
        printf("Case #%d: %I64d\n",cas,ans-tmp);

    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值