本博客为 OI 与 组合数学 (Combinatorics) 的结合
将 n + 1 n+1 n+1 个物体放入 n n n 个抽屉中,至少存在一个抽屉有两个物体
例题:Find a Multiple
https://acm.timus.ru/problem.aspx?space=1&num=1032
https://vjudge.net.cn/problem/EOlymp-5621
http://poj.org/problem?id=2356
以上三个网址都可以,看个人喜好,推荐用第二个https://vjudge.net.cn/problem/EOlymp-5621
题意
给你 n n n 个数,选出若干个使得他们的和为 n n n 的整数倍,输出这些数
思路
结论:一定存在一段连续子序列,使得他们的和为 n n n 的倍数
证明:
定义数组 s s s 为 数组 a a a 的前缀和 对 n n n 取模的值, s 0 = 0 , s 1 = a 1 m o d n , s 2 = ( a 1 + a 2 ) m o d n , . . . , s n = ( a 1 + a 2 + . . . + a n ) m o d n s_0=0, s_1=a_1 \bmod n,s_2=(a_1+a_2)\bmod n,\ ...\ ,s_n=(a_1+a_2+...+a_n) \bmod n s0=0,s1=a1modn,s2=(a1+a2)modn, ... ,sn=(a1+a2+...+an)modn
则共有 n + 1 n+1 n+1 个整数(注意下标是从 0 0 0 开始的)的范围是 0 ≤ s i ≤ n − 1 0 \le s_i \le n-1 0≤si≤n−1 且 s i s_i si 为整数
∵ 这个区间内的整数只有 n n n 个
∴ 必存在两个 s i s_i si 相等。
设
s
p
=
s
q
s_p=s_q
sp=sq ,则
s
q
−
s
p
=
0
s_q-s_p=0
sq−sp=0
{
s
q
−
s
p
=
∑
i
=
1
q
m
o
d
n
−
∑
i
=
1
p
m
o
d
n
=
∑
i
=
p
+
1
q
m
o
d
n
=
0
\begin{cases} \ \ \ \ s_q-s_p \\ =\displaystyle \sum_{i=1}^q \bmod\ n - \sum_{i=1}^p \bmod \ n \\ =\displaystyle \sum_{i=p+1}^q \bmod \ n \\ =0 \end{cases}
⎩
⎨
⎧ sq−sp=i=1∑qmod n−i=1∑pmod n=i=p+1∑qmod n=0
即:
(
a
p
+
1
+
a
p
+
2
+
.
.
.
+
a
q
)
m
o
d
n
=
0
(a_{p+1}+a_{p+2}+\ ...\ +a_q) \bmod n =0
(ap+1+ap+2+ ... +aq)modn=0
C++ 代码
无多余空格代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
int n;
int v[maxn];
int sum[maxn];
vector<pair<int,int> > ve;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>v[i];
}
for(int i=1;i<=n;i++){
sum[i]=(sum[i-1]+v[i])%n;
ve.push_back(make_pair(sum[i],i));
}
sort(ve.begin(),ve.end());
int i;
for(i=1;i<ve.size();i++){
if(ve[i].first==ve[i-1].first){
break;
}
}
cout<<ve[i].second-ve[i-1].second<<endl;
for(int s=ve[i-1].second+1;s<=ve[i].second;s++){
cout<<v[s]<<endl;
}
return 0;
}
标准版代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200005;
int n;
int v[maxn];
int sum[maxn];
vector<pair<int, int> > ve;
int main(){
cin >> n;
for (int i = 1; i <= n;i ++) {
cin >> v[i];
}
for (int i = 1; i <= n;i ++) {
sum[i] = (sum[i-1] + v[i]) % n;
ve.push_back(make_pair(sum[i], i));
}
sort (ve.begin(), ve.end());
int i;
for (i = 1; i < ve.size(); i ++) {
if (ve[i].first == ve[i-1].first) {
break;
}
}
cout << ve[i].second - ve[i-1].second << endl;
for (int s = ve[i-1].second+1; s <= ve[i].second; s ++) {
cout << v[s] << endl;
}
return 0;
}