【51Nod 1103】N的倍數(字首和,抽屜定理)詳細!!
阿新 • • 發佈:2018-11-12
Description
一個長度為N的陣列A,從A中選出若干個數,使得這些數的和是N的倍數。
例如:N = 8,陣列A包括:2 5 6 3 18 7 11 19,可以選2 6,因為2 + 6 = 8,是8的倍數。
先欣賞一下兩位大佬的程式碼
字首和:https://blog.csdn.net/qq_38735931/article/details/81590452?utm_source=blogxgwz1
抽屜原理:https://blog.csdn.net/dingchenxixi/article/details/52459001
思路:
用一個sum陣列記錄字首和,
先看簡單的:想想如何存在一個i,sum[i]%n==0,是不是以為這前i個數的和是n的倍數,也就滿足題目的要求,輸出即可;
下面就是麻煩一點的:假設所有的sum[i]都不符合上面的條件,那麼現在sum[i]的取值範圍是【1,n-1】,但是i是從【1,n】的,根據抽屜原理,肯定有i!=j, sum[i]==sum[j]存在,這樣他們的差值,也就是前j個數減去前i個數的那些數的和(假設j>i),一定是等於0的,也滿足咱們題目的條件。
如果細心看的話,你是肯定可以看懂的。
AC程式碼:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int main() { int a[50005],sum[50005],book[50005]; int n,i,j; scanf("%d",&n); memset(a,0,sizeof(a)); memset(book,0,sizeof(book)); memset(sum,0,sizeof(sum)); for(i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=(sum[i-1]+a[i])%n; } for(i=1;i<=n;i++) { if(!sum[i]) { printf("%d\n",i); for(j=1;j<=i;j++) printf("%d\n",a[j]); return 0; } if(book[sum[i]]!=0)//如果前面有一個sum[]等於現在的sum[i] { printf("%d\n",i-book[sum[i]]); for(j=book[sum[i]]+1;j<=i;j++) { printf("%d\n",a[j]); } return 0; } book[sum[i]]=i;//方便記錄某個sum[i]出現位置的下標 } // return 0; }