题意:给定一个长度为
现在,请你求出
考场上用暴力拿了
最暴力的方法就是枚举左右端点,复杂度为
接下来有考虑算贡献,枚举
这条路走不通,于是转而考虑计算序列里每个位置对答案得贡献。我们设
然后我们枚举
那么
那么对于每一个
最后记得离散化和开 long long。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
#define INF 1e9
using namespace std;
const long long maxn=1000101;
const long long mod=1e9+7;
const double Pi=acos(-1.0);
template<class T>void read(T &x)
{
x=0;long long f=0;char ch=getchar();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
long long n,a[maxn],b[maxn],cnt,c[maxn];
long long last[maxn],t1[maxn],t2[maxn];
long long ans=0,num=0;
long long lowbit(long long x)
{
return x&(-x);
}
void add(long long x,long long val)
{
for(long long i=x;i<=n;i+=lowbit(i))
{
t1[i]+=val;
t2[i]+=val*x;
}
}
long long query(long long x)
{
long long sum=0;
for(long long i=x;i;i-=lowbit(i))
sum+=t1[i]*(x+1)-t2[i];
return sum;
}//标准维护差分数组,用于区间修改和区间查询的树状数组板子
int main()
{
scanf("%lld",&n);
for(long long i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
cnt=unique(b+1,b+n+1)-b-1;
for(long long i=1;i<=n;i++)
{
a[i]=lower_bound(b+1,b+cnt+1,a[i])-b-1;
last[i]=c[a[i]];
c[a[i]]=i;
}
for(long long i=1;i<=n;i++)//枚举r
{
num=(num+i-last[i]+2*(query(i)-query(last[i])))%mod;//新的i,相当于上一个r+1,统计答案
ans=(ans+num)%mod;
add(last[i]+1,1);//i相当于r
add(i+1,-1);
}
printf("%lld",ans%mod);
return 0;
}