7.25 鸽巢原理,中国剩余定理,欧拉函数

Posted raincle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了7.25 鸽巢原理,中国剩余定理,欧拉函数相关的知识,希望对你有一定的参考价值。

A题:给你一个序列,长度为n。问是否存在一个连续的子序列和是m的倍数

鸽巢原理,求出序列的前缀和数组,若pre[i]%m==pre[j]%m,则(pre[j]-pre[i])%m==0;

 

B题:给出5个整数a,b,c,d,k。你要在[a,b]中找一个x,在[c,d]中找一个y,使得gcd(x,y)=k。请输出所有可能的组合数。
注意(x=5, y=7) 和 (x=7, y=5)是一样的。所有数据a=c=1;

gcd(x,y)=k,则gcd(x/k,y/k)=1,问题转化为求有多少组互素的x,y;

我们将b/=k;d/=k;枚举从1到b每一个x,求在(1,d)区间有多少与x互素的数;用容斥原理来求,与x互素的数的个数等于(d-与x不互素的元素的个数)=(d-与x有相同因子的元素的个数);

故将x质因数分解,套用容斥模板即可;

这里注意,因为(5,7)(7,5)是一样的,所以我们枚举1到min(b,d)的x,将x 质因数分解,然后求区间[x,d]与x互素的元素的个数(为什么这里是[x,d]不是[x+1,d]是因为1与1互素,如果要写[x+1,d]最后让ans++即可;)(为什么是[x,d]而不是[1,d],是因为避免重复,例如x=2,你找到了3,5,7;那么在找3,5,7的时候,你又把2算了一遍,所以我们总是从大于等于x的区间找;

这里特别注意区间和问题,求[l,r]=solve(r)-solve(l-1);(不要把 l 这个点给剪掉了)

 

技术分享图片
 1 #include <iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 #define LL long long
 7 const int maxn=1e6;
 8 int cnt,p=0;
 9 bool isprime[maxn];
10 int prime[maxn];
11 int prime_n[maxn];
12 void init()
13 {
14     LL i,j;
15     for(i=2;i<maxn;i++)
16     {
17         if(!isprime[i])
18         {
19             prime[p++]=i;
20             for(j=i*i;j<maxn;j+=i)
21                 isprime[j]=true;
22         }
23     }
24 }
25 void only(LL n)
26 {
27     LL i,j;
28     cnt=0;
29     for(i=0;i<p&&prime[i]*prime[i]<=n;i++)
30     {
31        if(n%prime[i]==0)
32        {
33            prime_n[cnt++]=prime[i];
34            while(n%prime[i]==0)
35            {
36                n/=prime[i];
37            }
38        }
39     }
40     if(n>1)prime_n[cnt++]=n;
41 }
42 LL solve(LL r)
43 {
44     LL i,j,ans=0;
45     for(i=1;i<(1<<cnt);i++)
46     {
47         LL tnt=0,mult=1;
48         for(j=0;j<cnt;j++)
49         {
50             if((i>>j)&1)
51             {
52                 mult*=prime_n[j];
53                 tnt++;
54             }
55         }
56         if(tnt&1)ans+=r/mult;
57         else ans-=r/mult;
58     }
59     return r-ans;
60 }
61 int main()
62 {
63     init();
64     int t;
65     cin>>t;
66     int T=1;
67     while(t--)
68     {
69         int a,b,c,d,k;
70         scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
71         if(k==0||k>b||k>d)printf("0
");
72         else
73         {
74           b/=k;
75           d/=k;
76           int n=min(b,d);
77           int m=max(b,d);
78           LL ans=0;
79           int res,i;
80           for(i=1;i<=n;i++)
81          {
82              only(i);
83              ans+=solve(m)-solve(i-1);
84          }
85          printf("Case %d: %lld
",T,ans);
86         }
87         T++;
88     }
89     return 0;
90 }
View Code

 

C题:欧拉树

发现树的两边是完全对称的,只看左边,递归求解,最简分式上下互素,对于n,存在以n为分母的个数为n的欧拉数

 

D题:HHM非常喜欢读书,已知他每天看a1页,那么最后还有b1页没有看;看a2页,还有b2页没有看....看ak页还有bk页没有看。请问这本书有多少页

典型的中国剩余算法问题

即xmod a1=b1;

xmod a2=b2;

xmod a3=b3;

.......

因为题目没有说a1,a2,..an互素,所以用不互素的中国剩余定理模板即可。

求出来的数即为最小满足条件的x

 

技术分享图片
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 typedef long long LL;
 5 typedef pair<LL, LL> PLL;
 6 LL a[100000], b[100000], m[100000];
 7 LL gcd(LL a, LL b){
 8     return b ? gcd(b, a%b) : a;
 9 }
10 void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
11     if (!b) {d = a, x = 1, y = 0;}
12     else{
13         ex_gcd(b, a % b, y, x, d);
14         y -= x * (a / b);
15     }
16 }
17 LL inv(LL t, LL p){//如果不存在,返回-1
18     LL d, x, y;
19     ex_gcd(t, p, x, y, d);
20     return d == 1 ? (x % p + p) % p : -1;
21 }
22 PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组
23     LL x = 0, m = 1;
24     for(int i = 0; i < n; i ++) {
25         LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
26         if(b % d != 0)  return PLL(0, -1);//答案,不存在,返回-1
27         LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
28         x = x + m*t;
29         m *= M[i]/d;
30     }
31     x = (x % m + m ) % m;
32     return PLL(x, m);//返回的x就是答案,m是最后的lcm值
33 }
34 int main(){
35     int n;
36     while(scanf("%d", &n) != EOF){
37         for(int i = 0; i < n; i ++){
38             a[i] = 1;
39             scanf("%d%d", &m[i], &b[i]);
40         }
41         PLL ans = linear(a, b, m, n);
42         if(ans.second == -1) printf("-1
");
43         else printf("%I64d
", ans.first);
44     }
45 }
View Code

 


以上是关于7.25 鸽巢原理,中国剩余定理,欧拉函数的主要内容,如果未能解决你的问题,请参考以下文章

使用中国剩余定理CRT对RSA运算进行加速

bzoj 1951: [Sdoi2010]古代猪文 中国剩余定理+欧拉定理+组合数学+卢卡斯定理

联赛前的复习计划

欧拉定理及扩展

退役前的数学学习

RSA加密与实践