7 1 1 2 3 4 4 5 3 1 2 3 0
7 10 12
/*分析: dp[i]表示区间长度为i时的个数 则从区间长度i-1到i减少了最后一个i-1长度的区间 记last[i]表示最后一个区间长度为i的不同数的个数 所以dp[i]=dp[i-1]-last[i-1] 同时从区间i-1长度到i增加了n-i+1个数 增加的数为a[i],a[i+1],a[i+2]...a[n] 则增加的这些数表示区间长度为i且以a[i...n]结尾 有多少是不能增加的呢? 比如a[1]~a[i-1]存在a[i],以a[i]结尾的区间长度为i的区间就不用增加a[i]这个数 在这里预处理时以a[i]结尾的区间长度为l~r不能增加 则l=i-pos[a[i]]+1;//pos[a[i]]表示i位置前出现的a[i] r=i-1+1+1 用树状数组能快速的累加 所以最终增加的是n-i+1-Query(i) */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <queue> #include <algorithm> #include <map> #include <cmath> #include <iomanip> #define INF 99999999 typedef __int64 LL; using namespace std; const int MAX=1000000+10; int n,m; int pos[MAX],a[MAX]; LL dp[MAX],last[MAX],c[MAX]; int lowbit(int x){ return x&(-x); } void Update(int x,int d){ while(x<=n){ c[x]+=d; x+=lowbit(x); } } LL Query(int x){ LL sum=0; while(x>0){ sum+=c[x]; x-=lowbit(x); } return sum; } int main(){ while(~scanf("%d",&n),n){ memset(pos,-1,sizeof pos); memset(c,0,sizeof c); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); if(pos[a[i]] != -1){ Update(i-pos[a[i]]+1,1); Update(i-1+2,-1); } pos[a[i]]=i; } memset(pos,-1,sizeof pos); memset(last,0,sizeof last);//last记录最后面的长度为i的不同数的个数 for(int i=n;i>=1;--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=0;i<m;++i){ scanf("%d",&n); printf("%I64d\n",dp[n]); } } return 0; }
hdu4455之树状数组+DP,布布扣,bubuko.com
原文:http://blog.csdn.net/xingyeyongheng/article/details/25833549