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;
}
版权声明:来自: 码代码的猿猿的AC之路 http://blog.csdn.net/ck_boss
原文:http://blog.csdn.net/ck_boss/article/details/47761357