Day 11 数论

第一题 鸽巢定理

 1 #include <iostream>
 2 using namespace std;
 3 const int N=100000+5;
 4 int a[N],q[N];
 5 int main()
 6 {
 7     int T,n,m;
 8     int ans=0;
 9     int q;
10     cin>>T;
11     while(T--)
12     {
13         cin>>n>>m;
14         for(int i=0;i<n;i++)
15         {
16             cin>>a[i];
17         }
18         for (int j=0;j<n;j++)
19         {
20             ans+=a[j];
21             q[j]=ans%m;
22         }
23         q=ans%m;
24         for(int t=0;t<n;t++)
25         {
26             if
27         }
28         if (q==0)  cout<<"YES"<<endl;
29         else cout<<"no"<<endl;
30 
31     }
32 }
我的代码 卒于第二个判断条件

100000,又用两个for显然超时

正确代码,结构好一万倍,但思路还是那个:

 1 #include <iostream>
 2 using namespace std;
 3 const int N=100000+5;
 4 bool a[N];
 5 int sum[N];
 6 
 7 int main ()
 8 {
 9     int T;
10     cin>>T;
11     while (T--)
12     {
13      int n,m;
14     cin>>n>>m;
15     for(int j=0;j<N;j++)
16     {
17         a[j]=0;
18         sum[j]=0;
19     }
20     int flag=0;a[0]=1;
21     for (int i=1;i<=n;i++)
22     {
23         int u;
24         cin>>u;
25         sum[i]=(sum[i-1]+u)%m;
26         if(a[sum[i]]) flag=1;
27         else a[sum[i]] = 1;
28     }
29     if(flag==1) cout<<"YES"<<endl;
30     else cout<<"NO"<<endl;
31     }
32 }

给你一个n个数的数列,一定有连续的m(m<=n)个数是n的倍数,可以简单证明下:
假设有一n个数的序列,把他们的前缀和存到S[i]数组中,代表从第1个到第i个相加的和,

把他们全对n取余,那范围肯定只有0~n-1这n个数,特判0,肯定yes,

那只剩下1~n-1了,如果没有0那n个数,不可能只有n-1种情况,所以必定有重复的,不妨假设S[i]%n == S[j]%n !=0 (i < j) 此时用(S[j]-S[i])%n肯定为0,也就是说i到j为连续的序列是n的倍数

根据上面的证明,最后我们只要求一个Sn(1~n之和)对m取余,看是否有=0的情况,或者有两个相等的情况就yes,否则no。 

 

第四题

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 using namespace std;
 5 typedef long long LL;
 6 typedef pair<LL, LL> PLL;
 7 const int N=100000+5;
 8 LL a[N],b[N],m[N];
 9 //模板大法好。。。
10 LL gcd(LL a,LL b)
11 {
12     return b?gcd(b,a%b):a;
13 }
14 
15 void ex_gcd (LL a,LL b,LL &x,LL &y,LL &d)
16 {
17     if(!b)
18     {
19         d=a;
20         x=1;
21         y=0;
22     }
23     else
24     {
25         ex_gcd(b,a%b,y,x,d);
26         y -= x*(a/b);
27     }
28 }
29 
30 LL inv(LL t ,LL p)
31 {
32     LL d,x,y;
33     ex_gcd(t,p,x,y,d);
34     return d==1?(x%p+p)%p:-1;
35 }
36 
37 PLL linear(LL A[], LL B[], LL M[], int n)
38  {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组
39     LL x = 0, m = 1;
40     for(int i = 0; i < n; i ++)
41         {
42         LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
43         if(b % d != 0)  return PLL(0, -1);//答案不存在,返回-1
44         LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
45         x = x + m*t;
46         m *= M[i]/d;
47     }
48     x = (x % m + m ) % m;
49     return PLL(x, m);//返回的x就是答案,m是最后的lcm值
50  }
51 
52 int main()
53 {
54     int k;
55     while (cin>>k&&k)
56     {
57         for(int i=0;i<k;i++)
58         {
59             a[i]=1;
60             cin>>m[i]>>b[i];
61         }
62         PLL ans =linear(a,b,m,k);
63         if(ans.second==-1) cout<<"-1"<<endl;
64         else cout<<ans.first<<endl;
65     }
66     return 0;
67 }

欧几里得

拓展欧几里得

模板

在这里学到的一点是 一个函数往回返回两个值要怎么返回  typedef  pair <LL, LL> PLL  

调用就是 PLL  ans   ;;;;   ans.firsst /ans.second....

posted @ 2018-07-25 17:14  行止  阅读(85)  评论(0编辑  收藏  举报