HDU 4455 Substrings第37回ACM/ICCC杭州試合区現場試合C題(DP)

9455 ワード

Substrings
Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 183    Accepted Submission(s): 42
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, 06, 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
 
 
Source
2012 Asia Hangzhou Regional Contest
 
 
この問題は考えにくいですが、問題を見ると、このデータの範囲を見て、クエリーの方法を見ます...木の形の配列や線分の木についてずっと考えています.
DPで解決しようと思えば難しくない.
DPの考え方O(n)複雑度で解決する.
例として、次のように説明します.
1 1 2 3 4 4 5;
明らかなdp[1]=n=7;
長さが1の場合は7区間あります.長さ1から長さ2まで、前の6つの区間を1つ後ろに増やし、最後の区間を取り除く.
増加した6つの数は、その区間で発生したかどうかによって決まります.前の等しい要素の距離が2より大きいかどうかを見てください.
だからdp[2]=dp[1]-1+4;
 
このように推すと,従ってdp値が得られる.
dp[i]=dp[i-1]-A+B;
減算Aは最後の長さi−1の区間の異なる数の個数であり,これは容易に前処理できる.
加算Bは、t番目の数からその前の数までの距離がi-1より大きい数である.
このB値も出やすいです.
前の数からの距離がiの数であることをs[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
",dp[t]); } } return 0; }