给定长为 \(m\) 的序列 \(a\),求一组 \(k,l\) 使得 \(m|\sum\limits^l_{i=k}a_i\)。
第一行输入 \(m\);
第二行输入 \(m\) 个数字,表示序列 \(a\)。
输出 \(k,l\)
保证 \(0\le m\le 2*10^5,0\le a_i\le 10^3\)。
保证数据在 \(int\) 范围内。
题解:证明存在性。若 \(a_1,a_1+a_2,a_1+a_2+a_3,\cdots,a_1+a_2+a_3+\cdots+a_m\) 中有任何一个可以被 \(m\) 整除那么结论就成立。设这 \(m\) 个和模 \(m\) 的余数为 \(r1, r2,r3,\cdots,r_m\),因为 \(x \mod m\) 的值只能是 \([0,m-1]\),所以定有两个余数相同,这里用到鸽巢原理。
设这两个相同余数为 \(a_1+a_2+\cdots+a_k=bm+r\) 和 \(a_1+a_2+\cdots+a_l=cm+r\)。我们将其作差得到 \(a_{k+1}+\cdots + a_l=(c-b)m\),故 \(a_{k+1}+\cdots+a_l\) 能被 \(m\) 整除。
那么这就优化了暴力枚举,我们用前缀和判同余即可,时间复杂度达到 \(O(n)\)。
代码:
#include <bits/stdc++.h>
#define rei register int
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define rep(i, s, n, c) for (register int i = s; i <= n; i+=c)
#define repd(i, s, n, c) for (register int i = s; i >= n; i-=c)
#define CHECK cout<<"WALKED"<<endl;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
#define pb push_back
#define ls id<<1
#define rs id<<1|1
const int INF = INT_MAX;
long long binpow(long long a, long long b, ll mod){long long res = 1; while (b > 0){if (b & 1) res = res * a % mod;a = a * a % mod; b >>= 1; } return res;}
using namespace std;
int a[200005], b[200005];
int main()
{
int m = read();
rep (i, 1, m, 1) {
a[i] = read();
a[i] += a[i - 1];
}
rep (i, 1, m, 1) {
int r = a[i] % m;
if (!b[r]) {
b[r] = i + 1;
} else {
printf("%d %d\n", b[r], i);
break;
}
}
return 0;
}
标签:le,int,cdots,ch,鸽巢,原理,运用,mod,define
From: https://www.cnblogs.com/CYLSY/p/17031067.html