Substrings
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1177 Accepted Submission(s): 356
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 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
Source
2012 Asia Hangzhou Regional Contest
题意:
给一个长度为n的数组,有q个询问w,输出区间长度为w的所有子序列中不同数的个数总和。
思路:
突破口是询问i与i+1有联系,所以要用DP解决该问题。
长度为i的区间变为长度为i+1的区间,变化为把长度为i的区间的最后一个区间删掉,然后从标号为i+1~n的元素依次添加到原来的第1~n-i的区间。
那么有 dp[i]=dp[i-1]-A+B;
A为最后i-1个元素的不同个数,这个好预处理,不多说了。
B则为标号为i+1~n的元素添到相应区间后看是否重复,不重复则+1。
B不太好处理,我们开一个数组s[i]记录所有元素中与其前面相等元素距离为i的有多少个,若一个元素前面没有相等的则这个元素即为其下标,对应的s[i]++。那么dp[i-1]到dp[i]递推时一个元素要加到i-1中的区间(即它前面的i-1个数中去),如果它不与前面i-1个数重复,那么就+1,从总体上来看就是加上s[i]~s[n]的累加和。把题目中的例子画几下就能知道其中的真理了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
//#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 105
#define MAXN 1000005
#define mod 1000000007
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;
int n,m,ans;
int a[MAXN];
int last[MAXN],pre[MAXN]; // last[]-每个元素与其前面元素最近距离 pre[]-辅助last的数组
int num[MAXN]; // num[i]-i~n中有多少个不同元素
int s[MAXN]; // s[i]-与其前面相等元素距离为i的有多少个 若前面没有相等的则为下标i
int sum[MAXN]; // sum[i]-s[i]~s[n]的和
ll dp[MAXN]; // 答案数组
void presolve()
{
int i,j;
memset(pre,0,sizeof(pre));
memset(s,0,sizeof(s));
for(i=1;i<=n;i++)
{
if(pre[a[i]]) last[i]=i-pre[a[i]];
else last[i]=i;
pre[a[i]]=i;
s[last[i]]++;
}
memset(pre,0,sizeof(pre));
num[n+1]=0;
for(i=n;i>=1;i--)
{
if(pre[a[i]]) num[i]=num[i+1];
else pre[a[i]]=1,num[i]=num[i+1]+1;
}
sum[n+1]=0;
for(i=n;i>=1;i--)
{
sum[i]=sum[i+1]+s[i];
}
}
void solve()
{
int i,j;
dp[1]=n;
for(i=2;i<=n;i++)
{
dp[i]=dp[i-1]-num[n-i+2]+sum[i];
}
}
int main()
{
int i,j,t;
while(scanf("%d",&n),n)
{
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
presolve();
solve();
scanf("%d",&m);
while(m--)
{
scanf("%d",&t);
printf("%I64d\n",dp[t]);
}
}
return 0;
}
/*
7
1 1 2 3 4 4 5
3
1
2
3
5
3 2 2 2 3
2
1
2
*/