Substrings(hdu 4455)

題意:ios

給定一個序列ai,個數爲n。再給出一系列w;對於每一個w,求序列中,全部長度爲w的連續子串中的權值和,子串權值爲子串中不一樣數的個數。數組

/*
    dp[i]表示長度爲i的序列不一樣元素個數之和。
    考慮從i-1向i轉移的時候,最後i-1個元素的貢獻會消失,記last[i]表示最後i個元素中不重複元素的個數,則轉移時,它的貢獻是-last[i]。 
    同時每一個序列會多出a[i],a[i+1],a[i+2]等元素,這些元素對答案有貢獻的前提是與前i-1個元素不重複。
    那麼i這個元素對答案有貢獻的範圍是pos[a[i]]-i+1~i+1(pos[i]表示i前面的元素是a[i]的位置),用樹狀數組累加一下。 
    因此轉移方程爲dp[i]=dp[i-1]+n-i+1-query(i)-last[i-1] 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1000010
#define lon long long
using namespace std;
int a[N],pos[N],c[N],last[N],n,m;
lon dp[N];
void updata(int x,int val){
    while(x<=n){
        c[x]+=val;
        x+=x&(-x);
    }
}
int query(int x){
    int tot=0;
    while(x){
        tot+=c[x];
        x-=x&(-x);
    }
    return tot;
}
int main(){
    while(1){
        scanf("%d",&n);
        if(!n) break;
        memset(pos,-1,sizeof(pos));
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++){
            if(pos[a[i]]!=-1){
                updata(i-pos[a[i]]+1,1);
                updata(i+1,-1);
            }
            pos[a[i]]=i;
        }
        memset(pos,-1,sizeof(pos));
        memset(last,0,sizeof(last));
        for(int i=n;i;i--){
            last[n-i+1]=last[n-i];
            if(pos[a[i]]==-1) last[n-i+1]++;
            pos[a[i]]=i;
        }
        dp[1]=n;
        for(int i=2;i<=n;i++)
            dp[i]=dp[i-1]+(n-i+1-query(i))-last[i-1];
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            int x;scanf("%d",&x);
            printf("%I64d\n",dp[x]);
        }
    }
    return 0;
}
相關文章
相關標籤/搜索