例1:http://lx.lanqiao.cn/problem.page?gpid=T444
蓝桥杯
问题描述
给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。
你能求出数列中总共有多少个K倍区间吗?
你能求出数列中总共有多少个K倍区间吗?
输入格式
第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)
以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)
输出格式
输出一个整数,代表K倍区间的数目。
分析:
1、因为(sum[r] - sum[l-1]) % k == 0,可推出sum[r] % k == sum[l - 1] % k.
2、因此,将前缀和分别对K取模。
3、分别统计出取模后的各数字的个数。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int MAXN = 100000 + 10; int sum[MAXN]; int cnt[MAXN]; int main(){ int N, K; scanf("%d%d", &N, &K); for(int i = 0; i < N; ++i){ scanf("%d", &sum[i]); } sum[0] %= K; for(int i = 1; i < N; ++i){ sum[i] = ((sum[i] % K) + sum[i - 1]) % K; } LL ans = 0; for(int i = 0; i < N; ++i){ ans += cnt[sum[i]]++; } printf("%lld\n", ans + cnt[0]); return 0; }
例2:https://cn.vjudge.net/problem/POJ-3370
题意:每个邻居可以给ai个糖,共n个邻居,问向哪几个邻居要糖可以正好被c个孩子平分。
分析:此题和例1解法相似。
若sum[i] % c == 0,则[1, i]可以被c整除;
若sum[l - 1] % c == sum[r] % c,则[l, r]可以被c整除;
由于输出任意一种答案即可,那会不会存在一种可能,就是答案都不是连续的区间,而是不连续的区间呢?
由于本题中c<=n,因此一定存在连续区间的解。
原因在于,
若sum[i]能被c整除,一定存在连续区间的解[1, i];
若sum[i]不能被c整除,则sum[i]%c可能的结果在[1, c-1]里,共c-1种可能,而c-1<n,根据抽屉原理,因此一定存在一对i, j,使得sum[i] % c == sum[j] % c,即存在连续区间解[i + 1, j].
#include<cstdio> #include<cstring> using namespace std; typedef long long LL; const int MAXN = 100000 + 10; int sum[MAXN]; int id[MAXN]; int main(){ int c, n; while(scanf("%d%d", &c, &n) == 2){ if(!c && !n) return 0; memset(sum, 0, sizeof sum); memset(id, 0, sizeof id); for(int i = 1; i <= n; ++i){ scanf("%d", &sum[i]); } sum[1] %= c; for(int i = 2; i <= n; ++i){ sum[i] = ((sum[i] % c) + sum[i - 1]) % c; } int st, et; for(int i = 1; i <= n; ++i){ if(sum[i] == 0){ st = 1; et = i; break; } if(id[sum[i]]){ st = id[sum[i]] + 1; et = i; break; } id[sum[i]] = i; } for(int i = st; i <= et; ++i){ printf("%d", i); if(i == et) printf("\n"); else printf(" "); } } return 0; }
例3:https://cn.vjudge.net/problem/POJ-2356
分析:与例2相似,因为N-1 < N,所以一定存在连续区间的解。
#include<cstdio> #include<cstring> using namespace std; typedef long long LL; const int MAXN = 15000 + 10; int a[MAXN]; int sum[MAXN]; int id[MAXN]; int main(){ int n; scanf("%d", &n); for(int i = 1; i <= n; ++i){ scanf("%d", &a[i]); } sum[1] = a[1] % n; for(int i = 2; i <= n; ++i){ sum[i] = ((a[i] % n) + sum[i - 1]) % n; } int st, et; for(int i = 1; i <= n; ++i){ if(sum[i] == 0){ st = 1; et = i; break; } if(id[sum[i]]){ st = id[sum[i]] + 1; et = i; break; } id[sum[i]] = i; } printf("%d\n", et - st + 1); for(int i = st; i <= et; ++i){ printf("%d\n", a[i]); } return 0; }