poj 2356 & poj 3370 鸽笼原理
题意:有n个数,从中取连续的一段,使其和为n的倍数。 3370求的是部分和为c的倍数(c<=n)。
分析:设前k个数的和 S(k)=a1+a2+...+ak,若S(k)为n的倍数,输出前k个数即可。否则 n 个 S(k) 除以 n 的余数只能有1,2,3...n-1,这(n-1)种情况,由鸽笼原理知,必有两个不同的和S(i)和S(j) (i<j)除以n的余数相同 ,故部分和S(j)-S(i) = ai+1+...+aj是n的倍数。
poj 2356
const int M = 10005; int n, s; int a[M], b[M]; int main(){ #ifndef ONLINE_JUDGE //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); #endif scanf("%d", &n); FOE(i, 1, n) scanf("%d", &a[i]); s = 0; b[0]=0; FOE(i, 1, n) { s = (s+a[i]) % n; if(s && b[s]==0) b[s]=i; else { printf("%d\n", i-b[s]); FOE(j, b[s]+1, i) printf("%d\n", a[j]); break; } } return 0; }
poj 3370
const int M = 100005; int n, c, s; int a[M], b[M]; int main(){ #ifndef ONLINE_JUDGE //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); #endif while(scanf("%d%d", &c, &n), c){ //memset(b, 0, sizeof b); FOE(i, 1, n) {scanf("%d", &a[i]); b[i]=0;} s = 0; b[0]=0; FOE(i, 1, n) { s = (s+a[i]) % c; if(s && b[s]==0) b[s]=i; else { FOE(j, b[s]+1, i) printf("%d ", j); printf("\n"); break; } } } return 0; }