P6477 [noi online ා 2 enhancement group] subsequence problem (folk data) solution

CSDN synchronization

Original question link

Brief question:

Given \ (n \) number \ (a {I \), find \ (\ sum {L = 1} ^ n \ sum {r = l} ^ n (f {L, R}) ^ 2 \), \ (f {L, R} \) is the number of distinct numbers in \ (a {L, a {L + 1} \ cdots a}).

\(\ text{NOI ONLINE 2} \) examination room \ (T2 \), which is more thoughtful.

Case 1

For \ (10 \% \) data, \ (n \leq 10 \)

Mischief.

Case 2

For \ (30 \% \) data, \ (n \leq 100 \)

Consider enumerating the left and right endpoints, then constructing the interval violently, and using \ (\ text{map} \) to de duplicate. \(O(n^3 \log n) \), score \ (30pts \)

To consider an optimization, you can first discretize the original array, and then use bucket, \ (O(n^3) \), score \ (30pts \)

Case 3

For \ (50 \% \) data, \ (n \leq 10^3 \)

In fact, for a fixed left endpoint \ (l \), it can be continuously extended to the right. For each new \ (r (l \leq r \leq n) \), only a new bucket is needed to maintain a number, so that \ (O(n^2) \) and score \ (50pts \)

In fact, I am sorry to stop here in the examination room!

Case 4

For \ (70 \% \) data, \ (n \leq 10^5 \)
For \ (100 \% \) data, \ (n \leq 10^6 \), \ (a \ I \ Leq 10 ^ 9 \)

First of all, discretize and reduce the value range. We need a data structure of \ (O(n \sqrt{n}) \) or \ (O(n \log n) \).

Note that the square is not easy to maintain, so:

Note that \ (x^2 = 2 \times \frac{x \times (x-1)}{2} + x \), if \ (g {L, R} = \ frac {f {L, R} \ times (f {L, R} - 1)} {2} \), then calculate each interval \ (g {L, R} + F {L, R} \).

Preprocessing \ (Last_i \) is to meet the largest \ (J \) in \ (a_i = a_j (1 \ Leq J < I) \), otherwise \ (Last_i=0 \)

The following enumeration \ (r \), just need to calculate \ (\ sum {L = 1} ^ r G {L, r} + F {L, r} \)

So what will be added if you consider \ (r \rightarrow r+1 \)?

First \ (\ sum f {L, R + 1} - F {L, R} = (R + 1) - last {R + 1} \), because \ (I \ in [last {R + 1} + 1, R + 1] \) obviously \ (f {I, R + 1} - F {I, R} = 1 \), one more \ (a {R + 1} \).

\(g {L, R} \) what's the matter?

Therefore, to maintain the value of \ (f {L, R} \), it is obvious that \ (r \rightarrow r+1 \) needs to let \ ([last {R-1} + 1, R + 1] \) interval \ (+ 1 \).

What about \ (\ sum g {L, R + 1} - \ sum g {L, R} \)? Consider a formula \ (\ frac{x \times (x+1)}{2} - \frac{x \times (x-1)}{2} = x \), so:

\[\sum g_{l,r+1} - \sum g_{l,r} = \sum_{l=Last_{r+1}+1}^{r+1} f_{l,r} \]

, you can continue to use segment tree maintenance.

Note: the final query result \ (\ times 2 \) is the final \ (g {L, R} \) value. This detail allows me to debug \ (0.5h \)

Time complexity: \ (O(n \log n) \)

Expected score: \ (100pts \)

Actual score: \ (75\) ~ \(100pts \) (\ (10 ^ 6 \) if you are stuck with a hard card, because your line tree must be open \ (\ text{long long} \), it is not necessary to pass, pay attention to constant optimization!)


//O3 optimized template
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(5000)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
//All i=-~i in the code is equivalent to i + +, which is used for the card
//register int can be regarded as int, which is used for card
//inline and fast read are both used for cards
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll MOD=1e9+7;
const int N=1e6+1;

#define L i<<1
#define R i<<1|1
#define DEBUG cout<<__LINE__<<" "<<__FUNCTION__<<endl;

inline int read(){char ch=getchar(); int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}

int n,a[N]; bool q[N];
map<int,int> uni; //Discretization tools
int b[N],last[N],gett[N]; //Get [i] maintain the last bucket
ll ans=0;

struct tree{
	int l,r; ll tag;
	ll sumi;
} t[N<<2];

inline void update(int i) {
	t[i].sumi=(t[L].sumi+t[R].sumi)%MOD;
}

inline void pass(int i,ll x) {
	t[i].tag=t[i].tag+x;
	t[i].sumi=(t[i].sumi+x*(t[i].r-t[i].l+1))%MOD;
}

inline void pushdown(int i) {
	pass(L,t[i].tag);
	pass(R,t[i].tag);
	t[i].tag=0;
}

inline void build_tree(int i,int l,int r) {
	t[i].l=l; t[i].r=r; t[i].sumi=0; t[i].tag=0;
	if(l==r) return;
	int mid=(l+r)>>1;
	build_tree(L,l,mid);
	build_tree(R,mid+1,r);
//	update(i);
}

inline ll query(int i,int l,int r) {
	if(l<=t[i].l && t[i].r<=r) return t[i].sumi;
	int mid=(t[i].l+t[i].r)>>1; ll ans=0;
	pushdown(i);
	if(l<=mid) ans=(ans+query(L,l,r))%MOD;
	if(r>mid) ans=(ans+query(R,l,r))%MOD;
	return ans; 
}

inline void change(int i,int l,int r,ll x) {
	if(l<=t[i].l && t[i].r<=r) {
		t[i].sumi=(t[i].sumi+x*(t[i].r-t[i].l+1))%MOD;
		t[i].tag=t[i].tag+x; return ;
	} pushdown(i);
	int mid=(t[i].l+t[i].r)>>1;
	if(l<=mid) change(L,l,r,x);
	if(r>mid) change(R,l,r,x);
	update(i);
} //Segment tree template

int main() {
	n=read();
	for(register int i=1;i<=n;i=-~i) a[i]=read(),b[i]=a[i];
	sort(b+1,b+1+n); int k=1; uni[b[1]]=1;
	for(register int i=2;i<=n;i=-~i) {
		if(b[i]!=b[i-1]) k++;
		uni[b[i]]=k;
	}
	for(register int i=1;i<=n;i=-~i) a[i]=uni[a[i]];
	for(register int i=1;i<=n;i=-~i) {
		last[i]=gett[a[i]];
		gett[a[i]]=i;
//		printf("%d %d\n",a[i],last[i]);
	} ll s=0; build_tree(1,1,n);
	for(register int r=0;r<n;r++) {
		ll t=r+1-last[r+1]; //ans=(ans+r-last[r])%MOD;
		t=(t+query(1,last[r+1]+1,r+1)*2)%MOD; //t is to add answers
		change(1,last[r+1]+1,r+1,1);
		s=(s+t)%MOD; ans=(ans+s)%MOD; //s is the current contribution, ans is the total answer, pay attention to modulus
	} printf("%lld\n",ans);
	return 0;
}

Posted by justin15 on Sun, 03 May 2020 09:42:54 -0700