hdu 4455 Substrings

来源:互联网 发布:周末算法定假日吗 编辑:程序博客网 时间:2024/06/11 13:31

题意:给定一个整数串,有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;}


原创粉丝点击