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
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 a 1,a 2…a n, 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<=10 6, 0<=Q<=10 4, 0<= a 1,a 2…a n <=10 6
Each test case starts with a positive integer n, the array length. The next line consists of n integers a 1,a 2…a n, 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<=10 6, 0<=Q<=10 4, 0<= a 1,a 2…a n <=10 6
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解决,我们可以观察到范围每增加1,集合的个数就会减少1,而且减少的是上一个状态的最后一个集合,我们用一个数组last来储存每个状态最后一个集合不同元素的个数。然后就是增加的那部分,如何知道呢?我们可以求出每个数距离上一次出现时下标差是多少,例如数字4,它第一次出现在下标2,第二次出现在了下标7,距离是5,如此类推。首先,我们用数组sum来统计各个距离一共有多少个数,因为只要距离大于等于该状态的范围我们就可以添加到该状态上。例如,dp[2]表示每两个数为一个集合,所有集合不同元素的个数总和。那么dp[2]=dp[1]-last[1]+(距离大于等于2的数的个数)。所以我们再用一个循环把sum从后累加到头就可以用sum来表示距离大于等于i时,有多少个数。最后用递推式:dp[i]=dp[i-1]-last[i-1]+sum[i];下面给代码。
#include<iostream>
#include<stack>
#include<cstring>
#include<map>
#include<string>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<utility>
using namespace std;
#define maxn 1000005
typedef long long LL;
int a[maxn], sum[maxn], last[maxn],vis[maxn];//sum表示距离大于等于i的元素有多少个,last表示q=i时,最后一个集合不同元素的个数。
LL dp[maxn];
int main() {
int n;
a[0] = -1;
while (scanf("%d", &n) != EOF) {
if (!n)
break;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; i++) {
sum[i - vis[a[i]]]++;
vis[a[i]] = i;
}
memset(vis, 0, sizeof(vis));
last[1] = 1;
vis[a[n]] = 1;
for (int i = n - 1,j=2; i >= 1; i--,j++) {
last[j] = last[j - 1];
if (vis[a[i]])
continue;
last[j]++;
vis[a[i]] = 1;
}
for (int i = n - 1; i >= 1; i--) {
sum[i] += sum[i + 1];
}
dp[1] = n;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] - last[i - 1] + sum[i];
}
int q;
scanf("%d", &q);
while (q--) {
int re;
scanf("%d", &re);
printf("%lld\n", dp[re]);
}
memset(vis, 0, sizeof(vis));
memset(sum, 0, sizeof(sum));
}
}