题目链接
选数 - 题目 - Daimayuan Online Judge
题目描述
给定 n 个正整数 。 要求从其中选出若干数字, 使得这些数字的和 mod n = 0 (对于每个下标最多只能选择一次)。
输入格式
第一行一个数字 n, 表示数字个数。
接下来一行 n 个整数 , 表示这 n 个数。
输出格式
第一行输出 M, 表示选择的数的个数。
第二行输出 M 个正整数, 用空格隔开, 表示这些数字的下标。
如果有多种方案满足要求, 输出任意一种。
如果没有满足要求的方案, 输出 −1。
样例输入
4
1 3 2 5
样例输出
2
2 4
样例解释
3 + 5 = 8, 8 mod 4 = 0。
数据规模
所有数据保证 ,。
解题思路
每个数先对 n 取模,这样得到 n 个在 0 ~ n - 1 的数,对这个数组求所有的前缀和 mod n,可以发现,如果有一个前缀和是 mod n = 0 的,那么直接从第一个数到这个数全选即可;如果所有前缀和都不为 0,因为一共有 n 个前缀和,但是每个前缀和 mod n 一定是在 0 ~ n - 1 的,根据抽屉原理,一定至少有两个前缀和 mod n 的值相等。那么只要找到这样的两个前缀和的下标记为 和 , 的数一定满足相加 mod n = 0,否则不可能在 前缀和的基础上加上这些数 mod n 还能让 前缀和与 前缀和相等。这样也就证明了本题不存在无解情况。
AC代码
#include <bits/stdc++.h>
#define lowbit(x) (x & -x)
#define mid (l + r >> 1)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 100005;
struct node{
int id, val;
bool operator < (const node &u) const{
return val < u.val;
}
}f[N];
int main(){
//freopen("input.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n;
cin >> n;
int pos = -1;
for(int i = 1; i <= n; i++){
cin >> f[i].val;
f[i].val = (f[i].val + f[i - 1].val) % n;
f[i].id = i;
if(f[i].val == 0) pos = i;
}
if(pos != -1){
cout << pos << endl;
for(int i = 1; i <= pos; i++)
cout << i << ' ';
cout << endl;
}
else{
sort(f + 1, f + n + 1);
int l, r;
for(int i = 1; i < n; i++){
if(f[i].val == f[i + 1].val){
l = min(f[i].id, f[i + 1].id);
r = max(f[i].id, f[i + 1].id);
break;
}
}
cout << r - l << endl;
for(int i = l + 1; i <= r; i++)
cout << i << ' ';
cout << endl;
}
return 0;
}