首页 > 其他 > 详细

luogu P6477 [NOI Online #2 提高组]子序列问题 |线段树

时间:2020-04-27 09:45:16      阅读:93      评论:0      收藏:0      [点我收藏+]

题目描述

给定一个长度为 \(n\) 的正整数序列 \(A_1\)?, \(A_2\)?, \(\cdots\), \(A_n\)。定义一个函数 \(f(l,r)\) 表示:序列中下标在 \([l,r]\) 范围内的子区间中,不同的整数个数。换句话说,\(f(l,r)\) 就是集合 \(\{A_l,A_{l+1},\cdots,A_r\}\) 的大小,这里的集合是不可重集,即集合中的元素互不相等。

现在,请你求出 \(\sum_{l=1}^n\sum_{r=l}^n (f(l,r))^2\)。由于答案可能很大,请输出答案对 109+710^9 +7109+7 取模的结果。

输入格式

第一行一个正整数 \(n\),表示序列的长度。

第二行 \(n\) 个正整数,相邻两个正整数用空格隔开,表示序列 \(A_1\), \(A_2\), \(\cdots\), \(A_n\)?。

输出格式

仅一行一个非负整数,表示答案对 \(10^9+7\) 取模的结果。


线段树里存f(l,r),注意下不要爆精度就好了

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long
#define int long long
const int N=1e6+5,mod=1e9+7;
inline int read(){
    int x=0; char ch=getchar();
    while(ch<‘0‘||ch>‘9‘)ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+(ch^48); ch=getchar();}
    return x;
}
int n,a[N],b[N];
#define ls p<<1
#define rs p<<1|1
#define mid ((l(p)+r(p))>>1)
struct Seg{
	int l,r,sum,add;
	#define l(x) tree[x].l
	#define r(x) tree[x].r
	#define sum(x) tree[x].sum
	#define add(x) tree[x].add
	#define len(x) (r(x)-l(x)+1)
}tree[N<<2];
void build(int p,int l,int r){
	l(p)=l,r(p)=r;
	if(l==r)return;
	build(ls,l,mid);
	build(rs,mid+1,r);
}
inline void pushdown(int p){
	sum(ls)+=add(p)*len(ls);
	sum(rs)+=add(p)*len(rs);
	sum(ls)%=mod;
	sum(rs)%=mod;
	add(ls)+=add(p);
	add(rs)+=add(p);
	add(ls)%=mod;
	add(rs)%=mod;
	add(p)=0;
}
void update(int p,int l,int r,int d){
	if(l(p)==r(p)){
		sum(p)=(sum(p)+len(p)*d)%mod;
		add(p)=(add(p)+d)%mod;
		return;
	}
	if(add(p))pushdown(p);
	if(l<=mid)update(ls,l,r,d);
	if(r>mid)update(rs,l,r,d);
	sum(p)=(sum(ls)+sum(rs))%mod;
}
int query(int p,int l,int r){
	if(l<=l(p)&&r(p)<=r)return sum(p);
	if(add(p))pushdown(p);
	int ans=0;
	if(l<=mid)ans+=query(ls,l,r);
	if(r>mid)ans=(ans+query(rs,l,r))%mod;
	return ans;	
}
int last[N];
signed main(){
	//freopen("sequence.in","r",stdin);
	//freopen("sequence.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++)a[i]=b[i]=read();
	sort(b+1,b+1+n);
	int len=unique(b+1,b+1+n)-b-1;
	for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+len,a[i])-b;
	build(1,1,n);
	ll op=0,ans=0;
	for(int l=n;l>=1;l--){
		if(last[a[l]]){
			op=(op+2*query(1,l,last[a[l]]-1)+(last[a[l]]-l))%mod;
			update(1,l,last[a[l]]-1,1);
		}
		else {
			op=(op+2*query(1,l,n)+(n-l+1))%mod;
			update(1,l,n,1);
		}
		last[a[l]]=l;
		ans=(ans+op)%mod;
	}
	cout<<ans<<endl;
}

luogu P6477 [NOI Online #2 提高组]子序列问题 |线段树

原文:https://www.cnblogs.com/naruto-mzx/p/12784245.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!