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;
}