計算子序列和是定值的子序列個數

題目以下:ios

Counting Subsequencesgit

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.dom

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

2 7 1 8 2 8 1 8 2 8優化

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

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.this

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

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;
}
相關文章
相關標籤/搜索