【题集】k倍区间(抽屉原理)

例1:http://lx.lanqiao.cn/problem.page?gpid=T444

蓝桥杯

问题描述

  给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。
  你能求出数列中总共有多少个K倍区间吗?

输入格式

  第一行包含两个整数N和K。(1 <= N, K <= 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;
}

  

原文地址:https://www.cnblogs.com/tyty-Somnuspoppy/p/8454521.html

时间: 2024-10-22 05:57:02

【题集】k倍区间(抽屉原理)的相关文章

2017蓝桥杯第十题(k倍区间)

1 #include<iostream> 2 #include<stdio.h> 3 using namespace std; 4 const int N = 10010; 5 int n,c[N*3],a[N]; 6 int lowbit(int n){ 7 return n&(-n); 8 } 9 void change(int k,int pos){ 10 while(pos<=n){ 11 c[pos]+=k; 12 pos+=lowbit(pos); 13

第八届蓝桥杯-k倍区间

历届试题 k倍区间 时间限制:2.0s 内存限制:256.0MB 提交此题 问题描述 给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间. 你能求出数列中总共有多少个K倍区间吗? 输入格式 第一行包含两个整数N和K.(1 <= N, K <= 100000) 以下N行每行包含一个整数Ai.(1 <= Ai <= 100000) 输出格式 输出一个整

k倍区间

用前缀和来求区间和,然后用一个二重循环穷举,但是因为问题规模为100000,所以超时(28分) 超时代码: #include <stdio.h> #include <memory.h> #include <math.h> #include <string> #include <string.h> #include <vector> #include <set> #include <stack> #include

鸽巢原理(抽屉原理)的详解

抽屉原理 百科名片 桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面放两个苹果.这一现象就是我们所说的“抽屉原理”. 抽屉原理的一般含义为:“如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有n+1或多于n+1个元素放到n个集合中去,其中必定至少有一个集合里有两个元素.” 抽屉原理有时也被称为鸽巢原理(“如果有五个鸽子笼,养鸽人养了6只鸽子,那么当鸽子飞回笼中后,至少有一个笼子中装有2只鸽子”).它是组合数学中一个重要的原理. 第一抽屉原理 原

糖果分发 - 抽屉原理

推荐博客: https://blog.csdn.net/dingchenxixi/article/details/52459001 抽屉原理的一种更一般的表述为:"把多于kn个东西任意分放进n个空抽屉(k是正整数),那么一定有一个抽屉中放进了至少k+1个东西. 利用上述原理容易证明:"任意7个整数中,至少有3个数的两两之差是3的倍数."因为任一整数除以3时余数只有0.1.2三种可能,所以7个整数中至少有3个数除以3所得余数相同,即它们两两之差是3的倍数. Every year

杭电dp题集,附链接

Robberies 点击打开链接 背包;第一次做的时候把概率当做背包(放大100000倍化为整数):在此范围内最多能抢多少钱  最脑残的是把总的概率以为是抢N家银行的概率之和- 把状态转移方程写成了f[j]=max{f[j],f[j-q[i].v]+q[i].money}(f[j]表示在概率j之下能抢的大洋); 正确的方程是:f[j]=max(f[j],f[j-q[i].money]*q[i].v)  其中,f[j]表示抢j块大洋的最大的逃脱概率,条件是f[j-q[i].money]可达,也就是

抽屉原理(鸽巢原理)

转至:https://blog.csdn.net/sand8o8time/article/details/77009749 一.抽屉原理初介绍: 桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面至少放两个苹果.这一现象就是我们所说的“抽屉原理”. 抽屉原理的一般含义为:“如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有n+1个元素放到n个集合中去,其中必定有一个集合里至少有两个元素.” 抽屉原理有时也被称为鸽巢原理.它是组合数学中一个重要的原

容斥原理和抽屉原理

转自:http://www.exam8.com/zige/gongwuyuan/xingzheng/sl/201408/2984187.html 一.容斥原理 在计数时,要保证无一重复,无一遗漏.为了使重叠部分不被重复计算,在不考虑重叠的情况下,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理. 1.容斥原理1——两个集合的容斥原理 如果被计数的事物有A.B两类,那么,先把A.B两个集合的元素个数相加,发

串-第4章-《数据结构题集》答案解析-严蔚敏吴伟民版

习题集解析部分 第4章 串 ——<数据结构题集>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑       本习题文档的存放目录:数据结构\▼配套习题解析\▼04 串       文档中源码的存放目录:数据结构\▼配套习题解析\▼04