Halloween treats - 鸽巢定理

题意

输入 cc 和 nn,代表有 cc 个孩子和 nn 户邻居。

接着一行输入 nn 个数字,代表万圣节时每户邻居会给孩子们的糖果数量。

孩子们想要去若干个邻居访问,然后拿到糖果。他们想要糖果能够平分,输出访问的邻居编号。

思路

题目规定了c<=n,从这里我们可以尝试找关系。由于是求最后能平分,我们直接在读入时就可以取模。然后发现得到的数列 0 <= ai <= c-1, 下一步我们怎么想都只能尝试对其求前缀和并取模,0 <= sumi <= c-1,这一步出现了sumi == 0,直接意味着这一段前缀是可以取得。然后看这个前缀和的范围,一共有c种可能性,而一旦有两个sum相等,意味着中间区间的和可以整除c,所以最极端的情况是sum取满了c-1种情况(因为不算0),而这是不可能的
因为: 1 < = ∀ s u m i < = c − 1 1<=\forall sum_i<=c-1 1<=sumi<=c1, s u m i ! = s u m j sum_i != sum_j sumi!=sumj 推出 1 < = i < = c − 1 1<=i<=c-1 1<=i<=c1,与题意 1 < = i < = n , n > = c 1<=i<=n,n>=c 1<=i<=n,n>=c不符,故必定存在一段连续区间使得 ∑ i = l r a i m o d c = 0 \sum_{i=l}^{r}a_i modc =0 i=lraimodc=0.

#include "bits/stdc++.h"

#define int long long
const int mod = 1e9 + 7;
const int maxn = 1e5+10;
using namespace std;
int sum[maxn];
int vis[maxn];
signed main() {
    
    
    ios ::sync_with_stdio(0);
    int t;
    int n,c;
    while (cin >> c >> n,!(c == 0 && n == 0)){
    
    
        memset(vis,0,sizeof vis);
        memset(sum,0,sizeof sum);
        int end = 0;
        for (int i = 1; i <= n; ++i) {
    
    
            int tmp;
            cin >> tmp;
            sum[i] = (sum[i- 1] + tmp) % c;
            if (!sum[i]) end = i;
        }
        if (end) {
    
    
            for (int i = 1; i <= end; ++i) {
    
    
                cout << i <<( (end == i)?'\n':' ');
            }
            continue;
        }
        for (int i = 1; i <=  n; ++i) {
    
    
            if (vis[sum[i]])
            {
    
    
                for (int j = vis[sum[i]]+1; j <= i; ++j) {
    
    
                    cout << j <<( (j == i)?'\n':' ');
                }
                break;
            } else
                vis[sum[i]] = i;
        }
    }
}

Guess you like

Origin blog.csdn.net/weixin_45509601/article/details/118803513