首页 > 代码库 > Vijos 连续数之和 (组合数学)

Vijos 连续数之和 (组合数学)

描述

有n个正整数排成一行。你的目的是要从中取出一个或连续的若干个数,使它们的和能够被k整除。

例如,有6个正整数,它们依次为1、2、6、3、7、4。若k=3,则你可以取出1、2、6,或者2、6、3、7,也可以仅仅取出一个6或者3使你所取的数之和能被3整除。当然,满足要求的取法不止以上这4种。事实上,一共有7种取法满足要求。

给定n和k,以及这n个数。你的任务就是确定,从这n个数中取出其中一个数或者若干连续的数使它们的和能被k整除有多少方法。

由于取法可能很多,因此你只需要输出它mod 1234567的值即可。

格式

输入格式

第一行有两个正整数,分别代表n和k。输入数据保证有n<=500 000,k<=100 000。

以下n行每行一个正整数。这些正整数保证都不大于10 000。

输出格式

一个正整数。它应该是你的答案mod 1234567的结果。

样例1

样例输入1

6 3126374
Copy

样例输出1

7
Copy

限制

各个测试点1s

来源

Matrix67 根据经典问题改编

 

技术分享
 1 /* 2     我们设sum为前缀和  3     首先要知道 4     (sum[j]-sum[i])%k==0 --> sum[j]%k==sum[i]%k 5     假设 sum[k]==sum[l]  那么 sum[k]-sum[l]==0 6     也就是 在[l+1,k]这段区间连续的和可以被k整除 7     那么假设 sum[i],sum[j],..sum[k](共bn个)  8     都是 MOD k 余数为k-1的sum  9     只需要从中任意取两个 就可以构成一个连续的区间的和可以整除k10     11     注意余数为0 要单独加一次 12 */13 #include<cstdio>14 #include<iostream>15 #define MAXN 50001016 #define MOD 123456717 18 using namespace std;19 20 int n,k;21 long long ans,a[MAXN];22 23 int b[100010];24 25 inline void read(int&x) {26     x=0;int f=1;char c=getchar();27     while(c>9||c<0) {if(c==-) f=-1;c=getchar();}28     while(c>=0&&c<=9) {x=(x<<1)+(x<<3)+c-48;c=getchar();}29     x=x*f;30 }31 32 inline int c(int N,int M) {33     return (N*(N-1)/2)%MOD;34 }35 36 int main() {37     int temp=0;38     read(n);read(k);39     for(int i=1;i<=n;i++) {40         read(temp);41         a[i]=a[i-1]+temp;42         ++b[a[i]%k];43     }44     ans+=b[0];45     for(int i=0;i<k;i++) {46         if(b[i]>=2)47           ans=(ans+c(b[i],2))%MOD;48     }49     printf("%lld\n",ans);50     return 0;51 }
代码

 

Vijos 连续数之和 (组合数学)