hdu4455之树状数组+DP

Substrings

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1571    Accepted Submission(s): 459

Problem Description

XXX has an array of length n. XXX wants to know that, for a given w, what is the sum of the distinct elements’ number in all substrings of length w. For example, the array is { 1 1 2 3 4 4 5 } When w = 3, there are five substrings of length 3. They are (1,1,2),(1,2,3),(2,3,4),(3,4,4),(4,4,5)

The distinct elements’ number of those five substrings are 2,3,3,2,2.

So the sum of the distinct elements’ number should be 2+3+3+2+2 = 12

Input

There are several test cases.

Each test case starts with a positive integer n, the array length. The next line consists of n integers a1,a2…an, representing the elements of the array.

Then there is a line with an integer Q, the number of queries. At last Q lines follow, each contains one integer w, the substring length of query. The input data ends with n = 0 For all cases, 0<w<=n<=106, 0<=Q<=104, 0<= a1,a2…an <=106

Output

For each test case, your program should output exactly Q lines, the sum of the distinct number in all substrings of length w for each query.

Sample Input

7
1 1 2 3 4 4 5
3
1
2
3
0

Sample Output

7
10
12
/*分析:
dp[i]表示区间长度为i时的个数
则从区间长度i-1到i减少了最后一个i-1长度的区间
记last[i]表示最后一个区间长度为i的不同数的个数
所以dp[i]=dp[i-1]-last[i-1]
同时从区间i-1长度到i增加了n-i+1个数
增加的数为a[i],a[i+1],a[i+2]...a[n]
则增加的这些数表示区间长度为i且以a[i...n]结尾
有多少是不能增加的呢?
比如a[1]~a[i-1]存在a[i],以a[i]结尾的区间长度为i的区间就不用增加a[i]这个数
在这里预处理时以a[i]结尾的区间长度为l~r不能增加
则l=i-pos[a[i]]+1;//pos[a[i]]表示i位置前出现的a[i]
r=i-1+1+1
用树状数组能快速的累加
所以最终增加的是n-i+1-Query(i)
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 99999999
typedef __int64 LL;
using namespace std;

const int MAX=1000000+10;
int n,m;
int pos[MAX],a[MAX];
LL dp[MAX],last[MAX],c[MAX];

int lowbit(int x){
	return x&(-x);
}

void Update(int x,int d){
	while(x<=n){
		c[x]+=d;
		x+=lowbit(x);
	}
}

LL Query(int x){
	LL sum=0;
	while(x>0){
		sum+=c[x];
		x-=lowbit(x);
	}
	return sum;
}

int main(){
	while(~scanf("%d",&n),n){
		memset(pos,-1,sizeof pos);
		memset(c,0,sizeof c);
		for(int i=1;i<=n;++i){
			scanf("%d",&a[i]);
			if(pos[a[i]] != -1){
				Update(i-pos[a[i]]+1,1);
				Update(i-1+2,-1);
			}
			pos[a[i]]=i;
		}
		memset(pos,-1,sizeof pos);
		memset(last,0,sizeof last);//last记录最后面的长度为i的不同数的个数
		for(int i=n;i>=1;--i){
			last[n-i+1]=last[n-i];
			if(pos[a[i]] == -1)++last[n-i+1];
			pos[a[i]]=i;
		}
		dp[1]=n;
		for(int i=2;i<=n;++i){
			dp[i]=dp[i-1]+(n-i+1-Query(i))-last[i-1];
		}
		scanf("%d",&m);
		for(int i=0;i<m;++i){
			scanf("%d",&n);
			printf("%I64d\n",dp[n]);
		}
	}
	return 0;
}

hdu4455之树状数组+DP

时间: 2024-10-10 05:56:14

hdu4455之树状数组+DP的相关文章

hdu 3030 Increasing Speed Limits (离散化+树状数组+DP思想)

Increasing Speed Limits Time Limit: 2000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 481    Accepted Submission(s): 245 Problem Description You were driving along a highway when you got caught by the road p

Codeforces 597C. Subsequences (树状数组+dp)

题目链接:http://codeforces.com/contest/597/problem/C 给你n和数(1~n各不同),问你长为k+1的上升自序列有多少. dp[i][j] 表示末尾数字为i 长度为j的上升子序列个数,但是dp数组是在树状数组的update函数中进行更新. update(i, val, j)函数表示在i的位置加上val,更新dp[i][j]. sum(i, j)就是求出末尾数字小于等于i 且长度为j的子序列有多少个. 1 //#pragma comment(linker,

【树状数组+dp+离散化】Counting Sequences

https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/G [题意] 给定一个数组a,问这个数组有多少个子序列,满足子序列中任意两个相邻数的差(绝对值)都不大于d. [思路] 首先,朴素的dp思想: dp[i]为以a[i]结尾的子问题的答案,则dp[i]=sum(dp[k]),k<i&&|a[k]-a[i]|<=d 但是时间复杂度为O(n^2),会超时. 我们可以这样想: 如果数组a排好序后,dp[i]就是区间(a[

hdu5125 树状数组+dp

hdu5125 他说的是n个人每个人都有两个气球a,b,气球各自都有相应的体积,现在让他们按照序号排列好来,对他们的a气球体积值计算最长上升子序列,对于这整个排列来说有m次机会让你将a气球替换成b气球(允许不使用完),问最后的最长上升子序列 的长度是多少,哈哈,当然用dp的思想我们很容易就能知道状态的转移 dp[1000][1000][2],但是苦于状态转移的复杂度太大了达到了 n*n*m肯定受不了,那好我们可以列出这个方程的转移方法 (0表示a气球1为b气球) dp[i][j][0]=max(

POJ 3378 Crazy Thairs(树状数组+DP)

[题目链接] http://poj.org/problem?id=3378 [题目大意] 给出一个序列,求序列中长度等于5的LIS数量. [题解] 我们发现对于每个数长度为k的LIS有dp[k][i][a[i]]=dp[k-1][i-1][0~a[i]-1] 我们用5个树状数组维护不同长度的LIS,递推即可,注意答案超过LL,需要用大数. [代码] #include <cstdio> #include <algorithm> #include <cstring> usi

hdu 2227 树状数组+dp

题意是求一个数列的不递减的子序列的个数: 很显然,如果只用dp来做的话时间是O(n*n) 因为dp[i]为前i个数可能的方案,则状态转移方程为dp[i]=sum(dp[j],j<i&&num[j]<=num[i])+1 对小数据坑定能过 但大数据就超时了,这里用到了树状数组来优化: 先对num按数来进行排序,(这道题因为数据较大  用到了离散化) 因为更新是是按原序更新的,及i之前的num[j]一定比num[i]小,维护了不递减的原则,更新是从mark[i](表示原序列i在排序

【树状数组+dp】HDU 5542 The Battle of Chibi

http://acm.hdu.edu.cn/showproblem.php?pid=5542 [题意] 给定长为n的序列,问有多少个长为m的严格上升子序列? [思路] dp[i][j]表示以a[i]结尾的长度为j的严格上升子序列有多少个 dp[i][j]=sum{dp[k][j-1]},k小于i且a[k]<a[i] 区间dp,复杂度为O(n^3) 会超时,第三层循环求和用树状数组加速 时间复杂度为O(n^2logn) 离散化的时候排序后不去重(否则WA) [Accepted] #include<

POJ 3378——Crazy Thairs(树状数组+dp+高精度)数据结构优化的DP

Crazy Thairs Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 6598   Accepted: 1636 Description These days, Sempr is crazed on one problem named Crazy Thair. Given N (1 ≤ N ≤ 50000) numbers, which  are no more than 109, Crazy Thair is a g

树状数组 + dp

//CodeForces 314C//分析:相当于求给定序列的不降子序列的个数,从一个空序列开始将得到的不降子序列不断的延长是典型的做法,则dp[i]表示以第 i 个元素结尾的序列//思路:O(n^2) 的做法,dp[i] = sum(dp[j]]) (a[j] <= a[i] && j <= i),求和过程用掉了 O(n) 的复杂度,用树状数组可以优化成 O(logn),需要先处理出每个元素在原来的序列中的大小顺序,最终复杂度 O(nlogn). 1 #include &qu