首页 > 其他分享 >hdu 5768 - 中国剩余定理 + 容斥

hdu 5768 - 中国剩余定理 + 容斥

时间:2023-05-31 12:01:13浏览次数:80  
标签:hdu gcd ll 容斥 5768 ans y1 x1 mx


题解思路:

利用中国剩余定理解决多个同余问题,这里需要再加一项mn = 7,an = 0,这样才能求出7的倍数的解,然后再需要用到容斥,2^15枚举就行了。

1.扩展欧几里得:

 

我们观察到:欧几里德算法停止的状态是: a= gcd(a,b), b = 0 ,那么,这是否能给我们求解 x y 提供一种思路呢?因为,这时候,只要 a = gcd(a,b)的系数是 1 ,那么只要 b 的系数是 0 或者其他值(无所谓是多少,反正任何数乘以 0 都等于 0 但是a 的系数一定要是 1),这时,我们就会有: a*1 + b*0 = gcd(a,b)

    当然这是最终状态,但是我们是否可以从最终状态反推到最初的状态呢?

    假设当前我们要处理的是求出 a 和 b的最大公约数,并求出 x 和 y 使得 a*x + b*y= gcd ,而我们已经求出了下一个状态:b 和 a%b 的最大公约数,并且求出了一组x1 和y1 使得: b*x1 + (a%b)*y1 = gcd , 那么这两个相邻的状态之间是否存在一种关系呢?

    我们知道: a%b = a - (a/b)*b(这里的 “/” 指的是整除,例如 5/2=2 , 1/3=0),那么,我们可以进一步得到:

        gcd = b*x1 + (a-(a/b)*b)*y1

            = b*x1 + a*y1 – (a/b)*b*y1

            = a*y1 + b*(x1 – a/b*y1)

    对比之前我们的状态:求一组 x 和 y 使得:a*x + b*y = gcd ,是否发现了什么?

    这里:

        x = y1

        y = x1 – a/b*y1

2.中国剩余定理:

用现代数学的语言来说明的话,中国剩余定理给出了以下的一元线性同余方程组:

 的整数也是方程组

的解。所以方程组所有的解的集合就是:

的数论倒数(

意义下的逆元)


在模

  

的意义下,方程组

  

只有一个解:


代码:

 

 

#include <iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int mx = 1e2+10;
ll x,y,n,l,r;
int m[mx],a[mx],num[mx],cnt;
void ex_euclid(ll a,ll b)
{
    if(!b){
        x = 1;
        y = 0;
    }else{
        ex_euclid(b,a%b);
        ll tem =x;
        x = y;
        y = tem - a/b*y;
    }
}
ll kuaisu(ll x,ll y,ll M){
    ll ans = 0;
    while(y){
        if(y&1) ans = (ans+x)%M;
        y >>= 1;
        x = x*2%M;
    }
    return ans;
}
ll China()
{
    ll M = 7,ans = 0,Mi;
    int pos;
    for(int i=0;i<cnt;i++) M *= m[num[i]];
    for(int i=0;i<cnt;i++)
    {
        pos = num[i];
        Mi = M/m[pos];
        ex_euclid(Mi,m[pos]);
        x = (x+m[pos])%m[pos];
        ans = (ans+kuaisu(a[pos]*Mi,x,M))%M;
    }
    return (r+M-ans)/M - (l-1+M-ans)/M;
}
int main(){
    int t,cas = 1;
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld%lld",&n,&l,&r);
        for(int i=1;i<=n;i++)
        scanf("%d%d",m+i,a+i);
        ll ans = r/7 - (l-1)/7;
        for(int i=1;i<(1<<n);i++){
            cnt = 0;
            for(int j=1;j<=n;j++)
            if((1<<(j-1))&i)  num[cnt++] = j;
            if(cnt&1) ans -= China();
            else ans += China();
        }
        printf("Case #%d: %lld\n",cas++,ans);
    }
    return 0;
}

 

 

 

 

 

标签:hdu,gcd,ll,容斥,5768,ans,y1,x1,mx
From: https://blog.51cto.com/u_12468613/6385893

相关文章

  • hdu 3038(种类并查集)
    题目大意:有n次询问,给出a到b区间的总和,问这n次给出的总和中有几次是和前面已近给出的是矛盾的解题思路:这道题第一次接触很难往并查集方向去思考。这里使用的并查集很灵活,不仅仅要记录其父亲节点,同时还要记录该节点到父亲节点的总和。在更新时,[l,r]要变成[l-1,r],比如有区间[1,2],[3,4......
  • hdu 2830(矩形dp)
    解题思路:这道题是hdu1505的更加强版本,实际上理解了前面的两道题,这道题很简单了,只是多了一个排序的过程。仔细想想,为什么会是多了排序的过程。因为我们的目标还是找到最大的全1矩阵,那么之前的思路肯定是不变的,关键就在于矩形的列是可以交换的,而且可以交换多次。其实这里不要多去想交......
  • hdu 1506(dp || 单调栈)
    题意:这题是要找最大的矩形面积。解题思路:这题的关键是要找每个条形能够往左和往右能够到达的最大长度。我最开始的思路是单调栈去维护,只要入栈的元素比栈顶元素小,栈顶就要出栈,并且知道其最右能够到达的最远距离。当要入栈的元素已经找到了位置,那么它左边的元素所在的位置就是其能到......
  • hdu 1516(编辑距离+记录路径)
    最开始把问题搞错了,以为是两个串都可以做修改,无论我怎么想都不通。回到这个题目上,这道题和最长公共子序列很相似,思路可以说是一样的,包括记录路径。其实也就是根据递推数组的结果来判断。#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;constintma......
  • hdu 2473(并查集+删除操作)
    解题思路:这道题有并查集的删除操作,如果直接对这一棵树进行删除节点操作肯定是很困难的。所以可以建立虚拟节点,只要有一个节点要被删除,就直接把它投影到虚拟节点上,即用这个虚拟节点来代替我们要删除的节点。这样我们就不需要用对已有的树形结构进行改动了。这个想法我在DragonBalls......
  • hdu 3635(并查集+路径压缩变形)
    解题思路:这道题想了我好久,因为我把城市的编号一起考虑进去了,结果想了好久都没A,最后看了别人的题解居然都没有考虑到城市的编号,不考虑城市编号的问题的话就是一个很水的并查集了。#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;constintMAXN=1000......
  • hdu 2874(LCA + 节点间距离)
    解题思路:Tarjan离线处理一篇介绍LCA的很好的博客:http://www.cppblog.com/menjitianya/archive/2015/12/10/212447.html#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;constintmaxn=10005;structEdge{ intk,next,cost;}edge[maxn&......
  • hdu 4027(线段树)
    题意:给定100000个数,两种操作,0ij表示将ij这段的数字都开根号(向下取整),1ij表示查询ij之间的所有值的和。。。(所有的和都不超过64位)解题思路:这题要做区间的开平方操作,2^64最多可以做8次开平方操作,所以对于每个节点最多只有8次操作,这道题如果lazy思想的话就要保存每个区间被开平方......
  • hdu 3564(线段树+LIS)
    题意:给出1~n的插入顺序,要求每次插入之后的LIS解题思路:这道题确实挺难想的,我最开始想用树状数组每插入一个数就更新一次,如果这么想,那么你就输了。它这里的想法是先将1-n的最终位置都保存起来,然后再一个个去找LIS。这里有点离线算法的意思,至少了解到更新时可以先别急着处理。还有这里......
  • hdu 3874(树状数组+离线算法)
    解题思路:这道题和之前的题一样,查找[l,r]区间内不重复数字的和。可以利用离线算法,实际上离线算法为了解决在查找时出现的矛盾,因为每次询问的区间大小不同,如果单独处理的话可能会对之后的查询有影响,所以离线算法帮助我们把要查询的区间先按照右端点进行排序,因为在处理更靠右的区间时,......