pre[i]第i位数往前走多少位碰到和它相同的数
dp[i]表示长度为i的子串,dp[i]可以由dp[i-1]加上从i到n的pre[i]>i-1的数减去最后一段长度为i-1的断中的不同的数得到....
爆int+有点卡内存....
7 1 1 2 3 4 4 5 3 1 2 3 0
7 10 12
/* *********************************************** Author :CKboss Created Time :2015年08月17日 星期一 22时06分06秒 File Name :HDOJ4455.cpp ************************************************ */ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <string> #include <cmath> #include <cstdlib> #include <vector> #include <queue> #include <set> #include <map> using namespace std; typedef long long int LL; const int maxn=1001000; int n; LL dp[maxn]; int a[maxn]; int pre[maxn]; int spre[maxn]; int wz[maxn]; bool vis[maxn]; /*************BIT*********************/ inline int lowbit(int x) { return x&(-x); } int tree[maxn]; void add(int p,int v) { for(int i=p;i<maxn;i+=lowbit(i)) tree[i]+=v; } LL sum(int p) { LL ret=0; for(int i=p;i;i-=lowbit(i)) ret+=tree[i]; return ret; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%d",&n)!=EOF&&n) { for(int i=1;i<=n;i++) scanf("%d",a+i); memset(wz,-1,sizeof(wz)); memset(pre,0,sizeof(pre)); memset(spre,0,sizeof(spre)); memset(tree,0,sizeof(tree)); memset(vis,false,sizeof(vis)); for(int i=n;i>=1;i--) { int x=a[i]; if(wz[x]==-1) wz[x]=i; else { spre[wz[x]-i]++; pre[wz[x]]=wz[x]-i; wz[x]=i; } } int zero=0,nozero; for(int i=1;i<=n;i++) { if(pre[i]==0) zero++; if(spre[i]) add(i,spre[i]); } int ed=n; int siz=0; nozero=n-zero; dp[1]=n; zero--; for(int i=2;i<=n;i++) { if(vis[a[ed]]==false) { vis[a[ed]]=true; siz++; } ed--; int B=siz; int A=zero+nozero-sum(i-1); dp[i]=dp[i-1]+A-B; if(pre[i]) nozero--,add(pre[i],-1); else zero--; } int Q; scanf("%d",&Q); while(Q--) { int x; scanf("%d",&x); printf("%lld\n",dp[x]); } } return 0; }