题目大意:
就是现在给出一个长度不超过10^6的数组, 数组中的每个数1 <= a[i] <= 10^6, 现在定义一个子串(a_l, a_(l + 1), ... a_r) 的权值为这个子串中的不同的数的个数, 现在, 对于Q次询问, 每次询问1 <= w <= n, 输出给出的数组中长度为w的所有子串数组的权值和
大致思路:
思路都在代码注释里了..
第一次写树状数组...
代码如下:
Result : Accepted Memory : 29060 KB Time : 1840 ms
/*
* Author: Gatevin
* Created Time: 2015/3/10 10:36:27
* File Name: Kotori_Itsuka.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
/*
* 用dp[i]表示询问的w = i的时候对应的答案, 显然dp[1] = n
* 那么对于给定的数组 a1, a2, .... an
* dp[1]的组是 {a_1}, {a_2}, {a_3}, ... {a_(n - 1)}, {a_n}
* dp[2]的组是 {a_1, a_2}, {a_2, a_3}, .... {a_(n - 1) a_n}
* dp[i]的组是 {a_1, a_2, a_3, ... a_i}, {a_2, a_3, .. a_(i + 1)},.. {a_(n - i + 1), .. a_n}
* 用tail[i]表示{a_(n - i + 1), ... a_n}的贡献值
* 那么dp[i] = dp[i - 1] - tail[i] + ask(i);
* 其中ask(i)表示dp[i]的分组中每一小组数加入新数之后的变化数
* 对于数a_(i + 1)为例
* 新加入的a_(i + 1)当它的上一次出现位置和这个位置的距离为 d 时
* 在所有所有dp[k] (k <= d)在转移是都会因为这个数得到贡献
* 所以需要用一个树状数组进行区间的更新, 然后再dp状态转移时进行单点查询即可
*/
#define maxn 1000010
int n, Q;
int a[maxn], w[10001], last[maxn], tail[maxn];//last[a[i]]为a[i]上一次出现的位置
lint dp[maxn];
lint C[maxn];
inline int lowbit(int x)
{
return -x & x;
}
void add(int pos, int value)
{
while(pos <= n)
C[pos] += value, pos += lowbit(pos);
return;
}
void update(int l, int r, int value)
{
add(l, value), add(r + 1, -value);
}
lint ask(int pos)
{
int ret = 0;
while(pos)
ret += C[pos], pos -= lowbit(pos);
return ret;
}
int main()
{
while(scanf("%d", &n), n)
{
for(int i = 1; i <= n; i++) scanf("%d", a + i);
scanf("%d", &Q);
for(int i = 1; i <= Q; i++) scanf("%d", w + i);
memset(dp, 0, sizeof(dp));
tail[1] = 1;
dp[a[n]] = 1;
for(int i = n - 1; i > 0; i--)
if(!dp[a[i]])
dp[a[i]] = 1, tail[n - i + 1] = tail[n - i] + 1;
else tail[n - i + 1] = tail[n - i];
memset(last, 0, sizeof(last));
memset(C, 0, sizeof(C));
for(int i = 1; i <= n; i++)
{
update(1, i - last[a[i]], 1);
last[a[i]] = i;
}
memset(dp, 0, sizeof(dp));
dp[1] = n;
for(int i = 2; i <= n; i++)
dp[i] = dp[i - 1] + ask(i) - tail[i - 1];
for(int i = 1; i <= Q; i++)
printf("%I64d\n", dp[w[i]]);
}
return 0;
}