把 n+1 件东西放入 n 个抽屉,则至少有一个抽屉里放两件或两件以上的东西。
从令一角度说,把 n-1 件东西放入 n 个抽屉,则至少一个抽屉是空的。
给出一个含有 n 个数字的序列,要找一个连续的子序列,使他们的和一定是 c 的倍数
假设 sum[i] 存储整数序列中的前 i 项和
根据抽屉原理,以 sum 数组构造抽屉 drawer 数组,其保存的是最先出现的 sum[i] 的下标,当 sum 的一个元素第二次放入重复的抽屉时,输出结果。
若 sum[i] 是 c 的倍数,直接输出前 i 项即可,若 sum[i] 不是 c 的倍数,则需要计算 sum[i]%c,此时,sum[i]%c = sum[j]%c,i!=j 肯定存在,即第 j 到第 i 项数的和为 c 的倍数。
LL a[N],drawer[N];
LL sum[N];
int main(){
LL c,n;
while(scanf("%lld%lld",&c,&n)!=EOF&&c&&n){
memset(drawer,-1,sizeof(drawer));
drawer[0]=0;
sum[0]=0;
for(LL i=1;i<=n;i++){//计算前缀和
scanf("%lld",&a[i]);
sum[i]=sum[i-1]+a[i];
}
for(LL i=1;i<=n;i++){
if(drawer[sum[i]%c]!=-1){
for(LL j=drawer[sum[i]%c]+1;j
做一件事,完成它有 n 类方式,第一类方式有 M1 种方法,第二类方式有 M2 种方法,…,第 n 类方式有 Mn 种方法,那么完成这件事共有 M1+M2+……+Mn 种方法。
例如:从北京到上海有火车、飞机、轮船 3 种方式,火车、飞机、轮船分别有 k1,k2,k3 个班次,那么从北京到上海有 k1+k2+k3 种方式可以到达。
做一件事,完成它要分成 n 个步骤,第一步有 M1 种不同的方法,第二步有 M2 种不同的方法,…,第 n 步有 Mn 种不同的方法,那么完成这件事共有 M1×M2×M3×…×Mn 种不同的方法。
例如:从北京乘坐火车到上海,需要转 3 次车,每次专车分别有 k1,k2,k3 个班次,那么从北京到上海有 k1×k2×k3 种方式可以到达。
分类加法原理和分步乘法原理是两个基本原理,回答的都是有关做一件事的不同方法种数的问题。
两者区别在于:分类计数原理针对的是分类问题,其中各种方法相互独立,用任何一种方法都可以完成这件事;分步计数原理针对的是分步问题,各步骤中的方法相互依存,只有各个步骤都完成才算完成事情。
分类要依据同一标准划分,既必须包括所有情况,又不要交错在一起产生重复;分步则应使各步依次完成,保证整个事件得到完成,既不得多余重复,也不缺少某一步骤。
根据研究对象的有无,一般将组合数学分为排列问题和组合问题。
其根本不同是排列问题与元素顺序有关,组合问题与元素顺序无关。
在排列与组合问题中,经常会出现计数问题,解决计数问题的思路一般有以下三种:
1)只取需要的。将各种符合条件的情形枚举出来,再利用加法原理求和。
2)先取后排。将各步符合条件的排列或组合计算出来,再根据乘法原理求积。
3)先全部取,再减去不要的。利用容斥定理,将各种符合条件的情形枚举出来,再减去不符合条件的。
关于容斥定理:点击这里