计算子序列和是定值的子序列个数

题目如下:

Counting Subsequences

Time Limit: 5000 MSMemory Limit: 65536 K

Description

"47 is the quintessential random number," states the 47 society. And there might be a grain of truth in that.

For example, the first ten digits of the Euler‘s constant are:

2 7 1 8 2 8 1 8 2 8

And what‘s their sum? Of course, it is 47.

You are given a sequence S of integers we saw somewhere in the nature. Your task will be to compute how strongly does this sequence support the above claims.

We will call a continuous subsequence of S interesting if the sum of its terms is equal to 47.

E.g., consider the sequence S = (24, 17, 23, 24, 5, 47). Here we have two interesting continuous subsequences: the sequence (23, 24) and the sequence (47).

Given a sequence S, find the count of its interesting subsequences.

Input

The first line of the input file contains an integer T(T <= 10) specifying the number of test cases. Each test case is preceded by a blank line.

The first line of each test case contains the length of a sequence N(N <= 500000). The second line contains N space-separated integers – the elements of the sequence. Sum of any continuous subsequences will fit in 32 bit signed integers.

Output

For each test case output a single line containing a single integer – the count of interesting subsequences of the given sentence.

Sample Input

2

13
2 7 1 8 2 8 1 8 2 8 4 5 9

7
2 47 10047 47 1047 47 47

Sample Output
3
4

这道题的意思就是给你一个整形的序列,让你计算满足和是47的子序列的个数。序列中的值可能有负数。

所以最直观的方法就是计算所有子序列的和,然后判断是否与47相等。算法的时间复杂度为O(N&sup3;),代码如下:

#include<iostream>
#include<vector>
#include<map>
#define N 47

using namespace std;

template<class type>
int countSubseq(const vector<type> &data)
{
	int count = 0;
	for(size_t i = 0; i < data.size(); ++i)
	{
		int sum = 0;
		for(int j = 0; j <= i; ++j)
		{
			int sum = 0;
			for(int k = j; k <= i; ++k)
			{
				sum += data[k];
			}
			if(sum == N)
			{
				++count;
			}
		}
	}
	return count;
}

int main()
{
	int nCase;
	cin >> nCase;
	for(int i = 0; i < nCase; ++i)
	{
		int n, d;
		cin >> n;
		vector<int> data(n, 0);
		for(int j = 0; j < n; ++j)
		{
			cin >> d;
			data[j] = d;
		}
		cout << countSubseq(data) << endl;
	}
	return 0;
}

通过分析可以看出程序存在许多重复计算,上一个sum可以进行一次加法运算得到下一个sum。经过再次优化使其时间复杂度变为O(N&sup2;),代码如下:

template<class type>
int countSubseq(const vector<type> &data)
{
	int count = 0;
	for(size_t i = 0; i < data.size(); ++i)
	{
		int sum = 0;
		for(int j = i; j < data.size(); ++j)
		{

			sum += data[j];
			if(sum == N)
			{
				++count;
			}
		}
	}
	return count;
}

但是程序依然超时,所以要设计出复杂度更低的算法才行。

设SUM[i,j] = A[i] + A[i+1] + ... + A[j] (0 <= i <= j < N),所以SUM[i, j] = SUM[0, j] - SUM[,0, i-1],也就是说只要求出所有的SUM[0, K] (K∈[0,N))就能计算出任意SUM[i, j].那么我们每次计算K的一种取值得到的SUM时,查找之前计算的SUM是否有与当前SUM差是47的K的个数,可以使用map来降低查找的复杂度,这样时间复杂度降为O(N),代码如下:

template<class type>
int countSubseq(const vector<type> &data)
{
	int count = 0, sum = 0;
	map<int, int> sumToSeqCnt;//存储和是sum的序列K的个数
	sumToSeqCnt[0] = 1;
	for(size_t i = 0; i < data.size(); ++i)
	{
		sum += data[i];
		sumToSeqCnt[sum]++;//计算和是sum的序列K的个数
		count += sumToSeqCnt[sum - N];
	}
	return count;
}

计算子序列和是定值的子序列个数

时间: 2024-10-11 08:10:31

计算子序列和是定值的子序列个数的相关文章

hdu 4352 数位dp(最长上升子序列的长度为k的个数)

http://acm.hdu.edu.cn/showproblem.php?pid=4352 Problem Description #define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then carefully reading the entire description is very important. As the strongest fighting force in UESTC, xhxj grew

最长递增子序列 &amp;&amp; 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离

http://www.cppblog.com/mysileng/archive/2012/11/30/195841.html 最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]<a[j],这样最长的子序列称为最长递增子序列. 设dp[i]表示以i为结尾的最长递增子序列的长度,则状态转移方程为: dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i]. 这样简单的复杂度为O(n^2),其实还有更好的方

最大上升子序列,最大下降子序列,最大非增子序列

For example,{1,5,2,4,3,5,6,4,7}的最大上升子序列是{1,2,3,5,6,7}长度为6 现已知原序列a[],如何求其最大上升子序列,最大下降子序列,最大非增子序列,最大非减子序列的长度?下面贴出两种方法:1.dp, 2.贪心+二分 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #defin

最大子序列和,最小子序列和,最小正子序列和,最大子序列乘积

来自:<数据结构与算法分析——C语言描述>练习2.12 一. 最大子序列和 1.穷举法,O(N3) 1 int maxSequenceSum1(const int A[], int N) 2 { 3 int i, j, k, maxSum, thisSum; 4 5 maxSum = 0; 6 for (i = 0; i < N; i++) 7 { 8 for (j = i; j < N; j++) 9 { 10 thisSum = 0; 11 for (k = i; k <

从数组中选出和等于固定值的n个数(JavaScript实现)

现实生活中的问题,可能会抽象为这样一种数据模型: 从一个数组中挑选出几个数,让这几个数相加的和为指定的值. 大多数读者应该有过网购的经历,网购一般会有个凑单功能,假如读者买了70元的商品,但是必须满100元才能包邮,这时系统会自动推荐一些商品,加起来差不多就100块钱了. 系统如何确定推荐哪些商品呢?这其实就是刚刚提到的模型,我们可以把热销商品的价格放到一个数组中,然后利用算法,找出数组中哪些价格的和为30元. 废话少说,小菜给大家分享一个JavaScript版本的算法实现. 算法代码: 1 f

ACdream ????计算最长连续相同字符的个数

计算最长连续相同字符的个数 测试数据 输入: aaaassdfg adasafag ssddffffgt 输出: 4 1 4 <span style="font-size:18px;">#include<stdio.h> #include<string.h> int main() { int i,n,t; int b[105]; char a[105]; scanf("%d",&t); while(t--) { n=0;

最长公共子序列和最长递增子序列

1.最长公共子序列:(x和y是两个数组的长度) f(x,y) = 0                               if(x==0 || y==0) f(x-1,y-1)+1               if(A[x-1]==B[y-1]) max{f(x-1,y), f(x,y-1)} if(A[x-1]!=B[y-1]) 2.最长递增子序列 (1) 最长公共子序列法:排序后与原数组的最长公共子序列. (2) 动态规划法:(时间复杂度O(N^2)) 设长度为N的数组为{a0,a1

寻找和为定值的多个数

1.首先看看简单的,寻找和为定值的2个数求解 采用HASH方式就可以求解. 具体参考这个文章: 寻找和为定值的2个数 2.那寻找和为定值的多个数怎么求解了 #include <stdio.h> #include <stdlib.h> /*原题:输入两个整数 n 和 m,从数列1,2,3.......n 中随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来 修改之后改为:对任意一个数组寻找m个数,使其和为指定的值*/ void findSubSum(int* a, int

和为定值的多个数

给定N个数,从中找出若干个数,使得这些数的和等于sum. TwoSum void TwoSum(int data[], unsigned int length, int sum) { std::sort(data, data + length); int begin = 0; int end = length - 1; while (begin < end) { int cur_sum = data[begin] + data[end]; if (cur_sum == sum) { printf