题意:询问一个序列所有长度为w的连续子序列中不相同数的个数之和。
思路居然是dp,关键一点是明确每次往序列增加数的时候这个序列的不相同数的个数只会增加或者不变。那我们可以预处理出每个数左边最进且与其相同的数的位置。然后一边递推算出所有的答案。
#include <iostream>
#include <cstring>
#include <cstdio>
#define lng long long
using namespace std;
const int maxn = 1000000 + 10;
int num[maxn], hash[maxn];
int dp1[maxn], n;
lng dp[maxn];
lng c[maxn];
inline int lowbit(int t) { return t & (-t); }
inline void add(int pos, int t) { while(pos > 0) { c[pos] += t; pos -= lowbit(pos); } }
inline lng sum(int pos) { lng s = 0; while(pos <= n) { s += c[pos]; pos += lowbit(pos); } return s; }
void prework()
{
memset(hash, 0, sizeof(hash));
memset(dp1, 0, sizeof(dp1));
memset(c, 0, sizeof(c));
for(int i = 1; i <= n; ++i) scanf("%d", num + i);
for(int i = n; i > 0; --i)
{
dp1[i] = (hash[num[i]]) ? dp1[i + 1] : dp1[i + 1] + 1;
hash[num[i]] = 1;
}
memset(hash, 0, sizeof(hash));
for(int i = 1; i <= n; ++i)
{
add(i - hash[num[i]], 1);
hash[num[i]] = max(hash[num[i]], i);
}
dp[1] = sum(1);
for(int i = 2; i <= n; ++i)
{
dp[i] = dp[i - 1] - dp1[n - i + 2];
dp[i] += sum(i);
}
}
void solve()
{
int q; scanf("%d", &q);
while(q--)
{
int w; scanf("%d", &w);
cout << dp[w] << "\n";
}
}
int main()
{
freopen("in.txt", "r", stdin);
while(~scanf("%d", &n) && n)
{
prework();
solve();
}
return 0;
}