Substrings
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 183 Accepted Submission(s): 42
Problem DescriptionXXX 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
InputThere are several test cases.
Each test case starts with a positive integer n, the array length. The next line consists of n integers a1,a2…an, 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<=106, 0<=Q<=104, 0<= a1,a2…an <=106
OutputFor 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 Input7 1 1 2 3 4 4 5 3 1 2 3 0
Sample Output7 10 12
Source2012 Asia Hangzhou Regional Contest 這題不容易想到,一看題目,看到這資料範圍,看到查詢的方式。。。一直在往樹狀數組或者線段樹方面去想。想到了用DP解決就不難了。用DP的思路O(n)複雜度解決。以範例為例說明:1 1 2 3 4 4 5;明顯dp[1]=n=7;長度為1的時候有7個區間。從長度為1到長度為2,就是把前6個區間往後增加一個數,把最後一個區間去掉。增加的6個數要看在該區間是否出現過,只要看它上一個相等的元素距離是否大於2所以dp[2]=dp[1]-1+4; 以此類推就可以得出所以的dp值了。dp[i]=dp[i-1]-A+B;減的A是最後一個長度為i-1的區間的不同數的個數,這個很容易預先處理得出來。加的B是第t個數到它上一個數的距離大於i-1的個數.這個B值也容易得出。用s[i]表示離上一個數的距離為i的個數,不斷減掉就得到B了。 具體看代碼:
//============================================================================// Name : HDU4455.cpp// Author : kuangbin// Version :// Copyright : Your copyright notice// Description :// DP////============================================================================#include <iostream>#include <stdio.h>#include <string.h>#include <algorithm>#include <math.h>using namespace std;const int MAXN=1000010;int a[MAXN];//1-n輸入的數列int f[MAXN];//f[i]表示a[i]在前面最近出現的位置,f[i]==0表示從左至右第一次出現int s[MAXN];//s[i]表示 t-f[t]==i,1<=t<=n的t的個數,即離上一個相等元素的距離為i的個數long long dp[MAXN];//需要輸出的結果int ss[MAXN];//ss[i]表示最後的i個數含有的不同元素的個數int main(){ int n; int m; while(scanf("%d",&n)==1 && n) { memset(f,0,sizeof(f)); memset(s,0,sizeof(s)); //順著求s數組 for(int i=1;i<=n;i++) { scanf("%d",&a[i]); s[i-f[a[i]]]++; f[a[i]]=i; } memset(f,0,sizeof(f));//f數組標記在後面是否出現過 ss[1]=1; f[a[n]]=1; for(int i=2;i<=n;i++) { if(f[a[n-i+1]]==0) { f[a[n-i+1]]=1; ss[i]=ss[i-1]+1; } else ss[i]=ss[i-1]; } dp[1]=n; int sum=n; //從dp[i-1]擴充到dp[i]就是去掉最後一個區間的個數,把前面的區間長度增加1, //加上相應增加的種類數 for(int i=2;i<=n;i++) { dp[i]=dp[i-1]-ss[i-1];//減掉最後一個區間的種類數 sum-=s[i-1]; dp[i]+=sum;//加上前面的區間增加一個長度後增加的種類數 } scanf("%d",&m); int t; while(m--) { scanf("%d",&t); printf("%I64d\n",dp[t]); } } return 0;}