题目大意:
就是现在给出一个长度不超过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; }