前缀和(vijos1090连续数之和)

描述

有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

6 3
1
2
6
3
7
4

样例输出1

7看到本题之后第一反应肯定是前缀和,但是用普通的前缀和并不可以成功Ac,而是tle。于是我们就可以从前缀和的公式出发sum[j]-sum[i-1]%k==0也就是sum[j]和sum[i-1]同余。我们就可以用一个book数组记录余数,然后用组合公式求出解即可。Tips:单独的一个book[0]也是可以算一种解的,所以答案要在最后加上book[0];这是我的代码~
#include<bits/stdc++.h>
#define mod 1234567
using namespace std;
int sum;
int book[2000000];
int n,m,k;
int ans=0;

int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>m;
		sum+=m;
		sum%=k;
		book[sum]++;
	}
	ans=book[0];
	for(int i=0;i<k;i++)
		ans+=book[i]*(book[i]-1)>>1;
	cout<<(ans)%mod<<endl;
	return 0;
}

  如果大家看不懂的话,可以看一下下面以为拷贝vijos大神的解析:Orz 340508965

先说说怎么做吧
SUM[i]是代表前i个数的和
当(SUM[i]-SUM[j]) MOD k=0 这时[j+1,i]就是满足的一个区间 一个方案了
而我们求的是(SUM[i]-SUM[j]) MOD k=0 这样的方案总个数
我们又可以推出 上式等价于SUM[i] MOD k=SUM[j] MOD k
所以我们就是求SUM[i] MOD k=SUM[j] MOD k 的方案个数了
假设 sum[i],sum[j],..sum[k](共bn个) 都是 MOD k 余数为k-1的sum
那么从上面bn个sum中任意选取两个就能得出(SUM[i]-SUM[j]) MOD k=0
那么在bn个sum中怎么配对呢
(下面的sum[bn]表示上述bn个sum中的第n个sum)
很简单 先是sum[b1]与sum[b2] sum[b3] ...sumbn
   然后sum[b2]与sum[b3] sum[b4] ...sumbn
   然后sum[b3]与sum[b4] sum[b5] ...sumbn
   ............
   最后sum[bn-1]与sum[bn]         ( 1 个)
   方案总数=n-1+n-2+n-3+...+1=bn*(bn-1) div 2
(好像这是初中的知识吧? 可是当时我看楼下的楼下的楼下....的题解 我一时竟然还不明白为什么)
所以 当sum mod k的余数为k-1时有bn*(bn-1) div 2个方案总数了
就这样依次得出余数为k-1 k-2 k-3 ...0的时候方案总数 再相加一下得出答案
所以在读入一个数的时候就计算sum然后计算sum mod k 的余数
而b[j]表示余数为j的sum个数 此时根据上面新得出的更新相应的b[j]
这样在读入完毕之后就可以根据b[j]直接计算总方案数了
特别值得注意的是!!!!
计算余数为0的方案总数时候还要加上b[0]  也就是b[0]*(b[0]-1) div 2+b[0]
为什么?? 因为余数为0的时候单独一个sum[i]就能成为一个方案了
还有比如div 2可以用shr 1 这样可以加快速度
呼呼(~ o ~)~zZ  说得好累啊
我自己都快被讲糊涂了 呵呵
希望有不懂这道题目的人能看懂....
这样就不算白忙了
 
时间: 2024-08-22 00:37:52

前缀和(vijos1090连续数之和)的相关文章

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 1234

2015年百度之星初赛(1) --- B 找连续数

找连续数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 179    Accepted Submission(s): 65 Problem Description 小度熊拿到了一个无序的数组,对于这个数组,小度熊想知道是否能找到一个k 的区间,里面的 k 个数字排完序后是连续的. 现在小度熊增加题目难度,他不想知道是否有这样的 k 的区

UVa 1210 连续素数之和

https://vjudge.net/problem/UVA-1210 题意: 输入整数n,有多少种方案可以把n写成若干个连续素数之和? 思路: 先素数打表,然后求个前缀和. 1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<queue> 6 using namespace std; 7 typedef long lon

[算法]正整数分解为几个连续自然数之和

题目:输入一个正整数,若该数能用几个连续正整数之和表示,则输出所有可能的正整数序列. 一个正整数有可能可以被表示为n(n>=2)个连续正整数之和,如: 15=1+2+3+4+5 15=4+5+6 15=7+8 有些数可以写成连续N(>1)个自然数之和,比如14=2+3+4+5:有些不能,比如8.那么如何判断一个数是否可以写成连续N个自然数之和呢? 一个数M若可以写成以a开头的连续n个自然数之和,则M=a+(a+1)+(a+2)+-+(a+n-1)=n*a+n*(n-1)/2,要求a!=0,否则

连续正整数之和(华东师范大学OJ-3025)

题目描述:一个正整数有可能可以被表示为 n(n>=2) 个连续正整数之和,如: 15=1+2+3+4+5 15=4+5+6 15=7+8 请编写程序,根据输入的任何一个正整数,找出符合这种要求的所有连续正整数序列. 输入数据:一个正整数,以命令行参数的形式提供给程序. 输出数据:在标准输出上打印出符合题目描述的全部正整数序列,每行一个序列,每个序列都从该序列的最小正整数开始.以从小到大的顺序打印.如果结果有多个序列,按各序列的最小正整数的大小从小到大打印各序列.此外,序列不允许重复,序列内的整数

正整数分解为几个连续自然数之和

题目:输入一个正整数,若该数能用几个连续正整数之和表示,则输出所有可能的正整数序列. 一个正整数有可能可以被表示为n(n>=2)个连续正整数之和,如: 15=1+2+3+4+5 15=4+5+6 15=7+8 有些数可以写成连续N(>1)个自然数之和,比如14=2+3+4+5:有些不能,比如8.那么如何判断一个数是否可以写成连续N个自然数之和呢? 一个数M若可以写成以a开头的连续n个自然数之和,则M=a+(a+1)+(a+2)+-+(a+n-1)=n*a+n*(n-1)/2,要求a!=0,否则

最大连续元素之和

Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14. Input The first line of the input contains an integer T(1<=T<

LeetCode 18. 4Sum (四数之和)

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target. Note: The solution set must not contain duplicate quadruplets. For exampl

给定数组A,大小为n,现给定数X,判断A中是否存在两数之和等于X

题目:给定数组A,大小为n,现给定数X,判断A中是否存在两数之和等于X 思路一: 1,先采用归并排序对这个数组排序, 2,然后寻找相邻<k,i>的两数之和sum,找到恰好sum>x的位置,如果sum=x则返回true, 3,找到位置后,保持i不变,从k处向前遍历,直到找到A[k]+A[i]等于x,并返回TRUE,如果找不到,则返回false. 论证步骤3:当前找到的位置恰好A[k]+A[i]>x,且前一位置的sum<x: 所以A[i]前面的数(不包括A[i])无论取哪两个数都