題意: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; }