HDOJ 4455 Substrings 递推+树状数组

pre[i]第i位数往前走多少位碰到和它相同的数

dp[i]表示长度为i的子串,dp[i]可以由dp[i-1]加上从i到n的pre[i]>i-1的数减去最后一段长度为i-1的断中的不同的数得到....

爆int+有点卡内存....

Substrings

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

Total Submission(s): 2300    Accepted Submission(s): 716

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

Source

2012 Asia Hangzhou Regional Contest

/* ***********************************************
Author        :CKboss
Created Time  :2015年08月17日 星期一 22时06分06秒
File Name     :HDOJ4455.cpp
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

typedef long long int LL;
const int maxn=1001000;

int n;
LL dp[maxn];
int a[maxn];
int pre[maxn];
int spre[maxn];
int wz[maxn];
bool vis[maxn];

/*************BIT*********************/

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

int tree[maxn];

void add(int p,int v)
{
	for(int i=p;i<maxn;i+=lowbit(i))
		tree[i]+=v;
}

LL sum(int p)
{
	LL ret=0;
	for(int i=p;i;i-=lowbit(i)) ret+=tree[i];
	return ret;
}

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);

	while(scanf("%d",&n)!=EOF&&n)
	{
		for(int i=1;i<=n;i++) scanf("%d",a+i);

		memset(wz,-1,sizeof(wz));
		memset(pre,0,sizeof(pre));
		memset(spre,0,sizeof(spre));
		memset(tree,0,sizeof(tree));
		memset(vis,false,sizeof(vis));

		for(int i=n;i>=1;i--)
		{
			int x=a[i];
			if(wz[x]==-1) wz[x]=i;
			else
			{
				spre[wz[x]-i]++;
				pre[wz[x]]=wz[x]-i;
				wz[x]=i;
			}
		}

		int zero=0,nozero;
		for(int i=1;i<=n;i++)
		{
			if(pre[i]==0) zero++;
			if(spre[i]) add(i,spre[i]);
		}
		int ed=n;
		int siz=0;
		nozero=n-zero;
		dp[1]=n; zero--;

		for(int i=2;i<=n;i++)
		{
			if(vis[a[ed]]==false)
			{
				vis[a[ed]]=true;
				siz++;
			}
			ed--;
			int B=siz;
			int A=zero+nozero-sum(i-1);
			dp[i]=dp[i-1]+A-B;
			if(pre[i]) nozero--,add(pre[i],-1);
			else zero--;
		}
		int Q;
		scanf("%d",&Q);
		while(Q--)
		{
			int x;
			scanf("%d",&x);
			printf("%lld\n",dp[x]);
		}
	}

    return 0;
}

版权声明:来自: 码代码的猿猿的AC之路 http://blog.csdn.net/ck_boss

时间: 2024-10-28 14:23:01

HDOJ 4455 Substrings 递推+树状数组的相关文章

HDU 4455 Substrings --递推+树状数组优化

题意: 给一串数字,给q个查询,每次查询长度为w的所有子串中不同的数字个数之和为多少. 解法:先预处理出D[i]为: 每个值的左边和它相等的值的位置和它的位置的距离,如果左边没有与他相同的,设为n+8(看做无穷). 考虑已知w=k的答案,推w = k+1时,这时每个区间都将增加一个数,即后n-k个数会增加到这些区间中,容易知道,如果区间内有该数,那么个数不会加1,,即D[i] > k时,结果++,即查询后n-k个数有多少个D[i] > k 的数即为要加上的数,然后最后面还会损失一个区间,损失的

hdoj 1166 敌兵布阵(树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 思路分析:该问题为动态连续和查询问题,使用数组数组可以解决:也可使用线段树解决该问题: 代码如下: #include <cstdio> #include <cstring> #include <iostream> using namespace std; const int MAX_N = 50000 + 10; int c[MAX_N]; inline int Lo

【算法#3】树状数组&amp;二叉索引树

其实是数据结构. 智推连续几天给我推树状数组的模板,还放在第一位-- 对着蓝书的图看了好几天才看懂,树状数组的另外一个名字是二叉索引树,指通过把一个数组抽象的变形成树状的以求得到树形数据结构的效果.有人说是线段树的阉割版,我不太清楚,树状数组应该是不支持区间修改加速的. 首先我们需要理解lowbit的概念,它指的是一个数转成二进制后位数最低的那个1表示的值.它具有一个特殊的性质但是为什么具有这个性质是无须证明也不用了解的. 然后我们画一个图,在一定范围内按lowbit的大小从上向下逐层分布,一层

hdu 4455 Substrings(树状数组+递推)

题目链接:hdu 4455 Substrings 题目大意:给定一个长度为N的序列,现在有Q次询问,每次给定一个w,表示长度,输出序列中长度为w的连续子序列 的权值和.序列的权值表示序列中不同元素的个数. 解题思路:递推,先预处理处每个位置和前面相同的数据的最短距离P.dp[i]表示说长度为i子序列的权值和,dp[i+1] = dp[i] + v - c.v为[i+1~N]中P值大于i的个数,我们可以看作将长度为i的子序列长度向后增加1,那么v则为增加长度带来 的权值增加值,c则是最后一个长度为

【HDOJ 5654】 xiaoxin and his watermelon candy(离线+树状数组)

pid=5654">[HDOJ 5654] xiaoxin and his watermelon candy(离线+树状数组) xiaoxin and his watermelon candy Time Limit: 4000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 233    Accepted Submission(s): 61 Problem Des

线段树(单点更新)/树状数组 HDOJ 1166 敌兵布阵

题目传送门 1 /* 2 线段树基本功能:区间值的和,修改某个值 3 */ 4 #include <cstdio> 5 #include <cstring> 6 #define lson l, m, rt << 1 7 #define rson m+1, r, rt << 1|1 8 9 const int MAX_N = 50000 + 10; 10 int sum[MAX_N<<2]; 11 12 void pushup(int rt) //

hdoj 1892(二维树状数组)

Problem H Time Limit : 5000/3000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other) Total Submission(s) : 8   Accepted Submission(s) : 3 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description Now I am leaving hust acm. In

线段树+树状数组+贪心 HDOJ 5338 ZZX and Permutations

题目传送门 1 /* 2 题意:不懂... 3 线段树+树状数组+贪心:贪心从第一位开始枚举,一个数可以是循环节的末尾或者在循环节中,循环节(循环节内部是后面的换到前面,最前面的换到最后面).线段树维护最大值,树状数组维护区间是否是循环节,查找前面最左边不是循环节的可用二分.我还是云里雾里的,看懂了网上的解题报告但还是不是完全明白题意:( 4 详细解释:http://blog.csdn.net/qq_24451605/article/details/47173933 5 */ 6 /******

HDOJ 5147 Sequence II 树状数组

树状数组: 维护每一个数前面比它小的数的个数,和这个数后面比他大的数的个数 再枚举每个位置组合一下 Sequence II Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 121    Accepted Submission(s): 58 Problem Description Long long ago, there is a seq