P6477 [NOI Online #2 提高组] 子序列问题

先离散化。记 \(A_i\) 上一次出现的位置为 \(last_{A_i}\),如果第一次出现则 \(last_{A_i}=0\)

考虑在末尾加入 \(A_i\) 产生的贡献,其实就是维护每个左端点和当前右端点形成的区间。对于 \(f(1\sim last_{A_i},i)\),其值不变仍然是 \(f(1\sim last_{A_i},i-1)\)。对于 \(f(last_{A_i}+1\sim i,i)\),其值加一。

这样我们需要一个数据结构来实现区间加一和全局求平方和,拆一波式子:

\[(x+y)^2=x^2+2xy+y^2 \]

用超级树状数组维护即可,另外记录下当前全局平方和,每次加上多出来的贡献。代码写得有点乱,注意 \(y\) 肯定是 \(1\)

code:

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
#define Mod 1000000007
#define For(i,x,y)for(i=x;i<=(y);i++)
#define lowbit(x)((x)&-(x))
int c1[N],c2[N],a[N],b[N],last[N],n;
int read()
{
	int A;
	bool K;
	char C;
	C=A=K=0;
	while(C<'0'||C>'9')K|=C=='-',C=getchar();
	while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
	return(K?-A:A);
}
int sum(int x)
{
	int ret=0,y=x;
	while(x)ret=(ret+1LL*c1[x]*(y+1)-c2[x]+Mod)%Mod,x-=lowbit(x);
	return ret;
}
void add(int x,int val)
{
	int y=x;
	while(x<=n)
	{
		c1[x]=(c1[x]+val)%Mod;
		c2[x]=(c2[x]+val*y+Mod)%Mod;
		x+=lowbit(x);
	}
}
int main()
{
	int i,m,ans,now;
	ans=now=0;
	n=read();
	For(i,1,n)a[i]=b[i]=read();
	sort(b+1,b+n+1);
	m=unique(b+1,b+n+1)-b-1;
	For(i,1,n)
	{
		a[i]=lower_bound(b+1,b+m+1,a[i])-b;
		now=(1LL*now+i-last[a[i]]+((1LL*sum(i)-sum(last[a[i]])+Mod)<<1))%Mod;
		add(last[a[i]]+1,1),add(i+1,-1);
		last[a[i]]=i;
		ans=(ans+now)%Mod;
	}
	cout<<ans;
	return 0;
}
posted @ 2021-06-06 20:08  Biadocy  阅读(37)  评论(0编辑  收藏  举报