题意:给定一个整数串,有Q组询问,问这个串中长度为W的子串中不同的数字之和为多少。
可以DP做,也可以用树状数组做。假设当前的数是a[i],如果它前面也出现了a[i]',那么a[i]'不计,计入的是a[i],如果a[i]后面出现了a[i]'',那么a[i]不计,计入的是a[i]''。定义a[i]前面的空位是bef,后面的空格是aft,则W在1-min(bef,aft)这段区间内的,a[i]的是要计算W次的,在min(bef,aft+1)-max(bef,aft)这段区间内,a[i]是要计算min(bef,aft)次的,在max(bef,aft)+1-bef+aft-1这段范围内,a[i]是要计算-W+bef+aft次的。明显看出这是一个一次函数。用两棵树状数组维护它们的系数就可以了。
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <string> #include <set> #include <map> #include <cmath> #include <algorithm> #include <queue> using namespace std; typedef long long LL; const int N=1e6+15; int pre[N],a[N],mx; int n,m; struct node { int valu,pos; node(){} node(int valu,int pos) : valu(valu),pos(pos) {} bool operator <(const node &b)const { return valu<b.valu||(valu==b.valu&&pos<b.pos); } }data[N]; struct BIT { LL T[N]; int lowbit(int x){return x&(-x);} void add(int st,int ed,int valu) { if(st>ed) return ; for(int i=st;i<=n;i+=lowbit(i)) T[i]+=valu; for(int i=ed+1;i<=n;i+=lowbit(i)) T[i]-=valu; } LL query(int pos) { LL sum=0; for(int i=pos;i>0;i-=lowbit(i)) sum+=T[i]; return sum; } }K,B; int main() { // freopen("C.in","r",stdin); // freopen("C.out","w",stdout); while(scanf("%d",&n)!=EOF) { if(n==0) break; mx=0; for(int i=1;i<=n;i++) { K.T[i]=B.T[i]=0; scanf("%d",&a[i]); mx=max(mx,a[i]); } for(int i=0;i<=mx;i++) pre[i]=-1; for(int i=n;i>=1;i--) { int bef=i,aft=n-i+1; if(pre[ a[i] ]!=-1) { aft=min(aft,pre[a[i]]-i); } pre[ a[i] ]=i; K.add(1,min(bef,aft),1); int st=min(bef,aft)+1; int ed=max(bef,aft); if(st<=ed) B.add(st,ed,min(bef,aft)); if(ed+1<=bef+aft-1) { K.add(ed+1,bef+aft-1,-1); B.add(ed+1,bef+aft-1,bef+aft); } } scanf("%d",&m); for(int i=0;i<m;i++) { LL tmp,ans=0; scanf("%I64d",&tmp); ans+=tmp*K.query(tmp); ans+=B.query(tmp); printf("%I64d\n",ans); } } return 0; }