1. 程式人生 > 其它 >python中的反射機制

python中的反射機制

日期:2022年5月19日

注:本部落格僅供參考


概念與基本思路

二分演算法是一種在有序陣列中查詢某一特定元素的查詢演算法。查詢過程從陣列的中間元素開始:如果中間元素正好是要查詢的元素,則查詢過程結束;如果某一特定元素大於或者小於中間元素,則在陣列大於或小於中間元素的那一半中查詢,而且跟開始一樣從中間元素開始比較。

與分治的關係

二分可以看作為一種特殊的分治

要求

資料一定要是有序的(單調的),不能亂序。

實現方法

用L(left)和R(right)代表某一區域的範圍。L與R相加除以二計算出中間值mid的值,若答案在mid的左邊,則R=mid-1;若答案在mid的右邊,則L=mid。重複這個過程,直到L與R中間只有一個元素,此時這個元素就是要尋找的答案。

程式碼

二分查詢

查詢小於等於某個數的最大值

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int len,n[10100],want;
 4 int main(){
 5     scanf("%d%d",&len,&want);
 6     sort(n,n+len);//預設是升序排列的
 7     int L=1,R=len,mid;
 8     while(L<R)
 9     {
10         mid=(L+R+1)/2;
11         if(n[mid]<=want)
12 { 13 L=mid; 14 }else{ 15 R=mid-1; 16 } 17 } 18 printf("%d",L); 19 return 0; 20 }

查詢大於等於它的最小值

 1  1 #include<bits/stdc++.h>
 2  2 using namespace std;
 3  3 const int N=1001000;
 4  4 int n,m,q,a[N];
 5  5 int L,R,mid;
 6  6 int main(){
 7
7 scanf("%d%d",&n,&m); 8 8 for(int i=1;i<=n;++i) 9 9 { 10 10 scanf("%d",&a[i]); 11 11 } 12 12 for(int i=1;i<=m;++i) 13 13 { 14 14 L=1,R=n; 15 15 scanf("%d",&q); 16 16 while(L<R) 17 17 { 18 18 mid=(L+R)/2; 19 19 if(a[mid]>=q) 20 20 { 21 21 R=mid; 22 22 }else{ 23 23 L=mid+1; 24 24 } 25 25 } 26 26 if(a[L]!=q) 27 27 { 28 28 printf("%d ",-1); 29 29 }else{ 30 30 printf("%d ",L); 31 31 } 32 32 } 33 33 return 0; 34 34 }

砍樹(P1873)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int tree=1000100;
 4 int N,M,trees[tree];
 5 int L,R,mid,mx=0;
 6 int check(int a){
 7     long long sum=0;
 8     for(int i=1;i<=N;++i)
 9     {
10         if(trees[i]>=a)
11         {
12             sum+=trees[i]-a;
13         }
14     }
15     return sum>=M;
16 }
17 int main(){
18     scanf("%d%d",&N,&M);
19     for(int i=1;i<=N;++i)
20     {
21         scanf("%d",&trees[i]);
22         mx=max(mx,trees[i]);
23     }
24     L=0,R=mx;
25     while(L<R)
26     {
27         mid=(L+R+1)/2;
28         if(check(mid))
29         {
30             L=mid;
31         }else{
32             R=mid-1;
33         }
34     }
35     printf("%d",L);
36     return 0;
37 }

木材加工(P2440)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,k,woods[100100];
 4 int L,R,mid,mx=0;
 5 int check(int a){
 6     long long sum=0;
 7     for(int i=1;i<=n;++i)
 8     {
 9         sum+=woods[i]/a;
10     }
11     return sum>=k;
12 }
13 int main(){
14     scanf("%d%d",&n,&k);
15     for(int i=1;i<=n;++i)
16     {
17         scanf("%d",&woods[i]);
18         mx=max(mx,woods[i]);
19     }
20     L=0,R=mx;
21     while(L<R)
22     {
23         mid=(L+R+1)/2;
24         if(check(mid))
25         {
26             L=mid;
27         }else{
28             R=mid-1;
29         }
30     }
31     printf("%d",L);
32     return 0;
33 }

跳石頭(P2678)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int L,N,M,rocks[50100];
 4 int l,r,mid;
 5 int check(int a){
 6     int sum=0,cu=0;
 7     for(int i=1;i<=N;++i)
 8     {
 9         if(rocks[i]-rocks[cu]<a)
10         {
11             ++sum;
12         }else{
13             cu=i;
14         }
15     }
16     return sum<=M;
17 }
18 int main(){
19     scanf("%d%d%d",&L,&N,&M);
20     for(int i=1;i<=N;++i)
21     {
22         scanf("%d",&rocks[i]);
23     }
24     l=0,r=L;
25     while(l<r)
26     {
27         mid=(l+r+1)/2;
28         if(check(mid))
29         {
30             l=mid;
31         }else{
32             r=mid-1;
33         }
34     }
35     printf("%d",l);
36     return 0;
37 }

A-B數對(P1102)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=200100;
 4 int n,c,a[N];
 5 int L,R,mid,sum=0;
 6 int main(){
 7     scanf("%d%d",&n,&c);
 8     for(int i=1;i<=n;++i)
 9     {
10         scanf("%d",&a[i]);
11     }
12     sort(a+1,a+n+1);
13     for(int i=1;i<=n-1;++i)
14     {
15         L=i+1,R=n;
16         while(L<=R)
17         {
18             mid=(L+R)/2;
19             if(a[mid]>=a[i]+c)
20             {
21                 R=mid-1;
22             }else{
23                 L=mid+1;
24             }
25         }
26         sum-=L;
27         L=i+1,R=n;
28         while(L<=R)
29         {
30             mid=(L+R)/2;
31             if(a[mid]>a[i]+c)
32             {
33                 R=mid-1;
34             }else{
35                 L=mid+1;
36             }
37         }
38         sum+=L;
39     }
40     printf("%d",sum);
41     return 0;
42 }

聰明的質監員(P1314)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=200100;
 4 int n,m,w[N],v[N],l[N],r[N],L,R,mid,c[N];
 5 long long s,sum[N];
 6 long long y(int a){
 7     memset(c,0,sizeof(c));
 8     memset(sum,0,sizeof(sum));
 9     for(int i=1;i<=n;++i)
10     {
11         c[i]=c[i-1]+(w[i]>=a);//這裡使用了字首和的知識
12     }
13     for(int i=1;i<=n;++i)
14     {
15         sum[i]=sum[i-1]+(w[i]>=a)*v[i];
16     }
17     long long res=0;
18     for(int i=1;i<=m;++i)
19     {
20         res+=(c[r[i]]-c[l[i]-1])*(sum[r[i]]-sum[l[i]-1]);
21     }
22     return res;
23 }
24 int main(){
25     scanf("%d%d%lld",&n,&m,&s);
26     for(int i=1;i<=n;++i)
27     {
28         scanf("%d%d",&w[i],&v[i]);
29     }
30     for(int i=1;i<=m;++i)
31     {
32         scanf("%d%d",&l[i],&r[i]);
33     }
34     L=0,R=1000000;
35     while(L<R)
36     {
37         mid=(L+R)/2;
38         if(y(mid)<=s)
39         {
40             R=mid;
41         }else{
42             L=mid+1;
43         }
44     }
45     long long ans=min(s-y(L),y(L-1)-s);
46     printf("%lld\n",ans);
47     return 0;
48 }

心得

  • 二分演算法雖然非常好用、高效,但做題時也要思考這道題是否需要使用二分演算法。
  • 二分演算法的二分查詢部分幾乎相等,變化的一般只是檢驗部分。
  • 二分演算法與一些其他的演算法/思想(如貪心、字首和等)一起使用可以實現意想不到的效果。如跳石頭(P2678)的檢驗函式:
     1 int check(int a){
     2  6     int sum=0,cu=0;
     3  7     for(int i=1;i<=N;++i)
     4  8     {
     5  9         if(rocks[i]-rocks[cu]<a)
     6 10         {
     7 11             ++sum;
     8 12         }else{
     9 13             cu=i;
    10 14         }
    11 15     }
    12 16     return sum<=M;
    13 17 }