[USACO 2020.1 Platinum][LOJ3247]Non-Decreasing Subsequences(CDQ分治)

题面

https://loj.ac/problem/3247

题解

考虑CDQ分治。对于(solve(l,r,v))(其中l,r表示当前处理到的区间的左右端点,v是一个vector,存放当前区间内待处理的所有询问的序号):

  • (m=(l+r)>>1)

  • 预处理出(f[i][j](1{leq}i{leq}k,l{leq}j{leq}r)),其中(f[i][j]=)

    [egin{cases} {以j为左端点,右端点{leq}m,且a[右端点]=i的不下降子序列数}(l{leq}j{leq}m) \ {以j为右端点,左端点{>m,且a[左端点]=i的不下降子序列数(m<j{leq}r)}} end{cases} ]

    对于(m<j{leq}r)来言,有递推式

    [f[i][j]={sumlimits_{m<k<j,a[k]{leq}a[j]}}f[i][k]+[a[j]=i]$$,这一过程可以用树状数组优化,从而在$O((r-l+1)klogk)$时间内完成预处理。 另外,需要将空字符串统计进去,就是把$f[1][m],f[k][m+1]$都加1。 接下来,对$f$进行前缀和,就可以得到$f[i][j]=$ $$egin{cases} {l{leq}左端点,右端点{leq}m,且a[右端点]=i的不下降子序列数}(l{leq}j{leq}m) \ {j{geq}右端点,左端点{>m,且a[左端点]=i的不下降子序列数(m<j{leq}r)}} end{cases}]

  • 遍历所有序号(id{in}v)。如果(R[id]{leq}m),将其加入数组vl。如果(L[id]>m),将其加入数组vr。

  • 对于其余id,统计答案:

    [{sumlimits_{i=1}^{k}}f[i][L[id]]{sumlimits_{j=i}^{k}}f[j][R[id]]$$。这一过程可以先计算前缀和来优化。 ]

依此过程,solve中预处理的总复杂度是(O(nklognlogk)),统计答案的总复杂度是(O(qk))

代码

#include<bits/stdc++.h>

using namespace std;

#define N 50000
#define Q 200000
#define ll long long
#define mod 1000000007
#define rg register
 
namespace ModCalc{
	inline void Inc(ll &x,ll y){
		x += y;if(x >= mod)x -= mod;
	}
	
	inline void Dec(ll &x,ll y){
		x -= y;if(x < 0)x += mod;
	}
	
	inline ll Add(ll x,ll y){
		Inc(x,y);return x;
	}
	
	inline ll Sub(ll x,ll y){
		Dec(x,y);return x;
	}
}
using namespace ModCalc;
 
inline ll read(){
	ll s = 0,ww = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
	while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
	return s * ww;
}

inline void write(ll x){
	if(x < 0)putchar('-'),x = -x;
	if(x > 9)write(x / 10);
	putchar('0' + x % 10);
}

ll n,q,k;
ll f[20+5][N+5],a[N+5],L[Q+5],R[Q+5];
ll ans[Q+5];
ll s[20+5];

struct BIT{
	ll b[20+5];
	
	inline ll lowbit(ll x){
		return x & -x;
	}
	
	inline void reset(){
		memset(b,0,sizeof(b));
	}
	
	inline void ud(ll x,ll dx){
		for(rg ll i = x;i <= k;i += lowbit(i))Inc(b[i],dx);
	}
	
	inline ll query(ll x){
		ll rt = 0;
		for(rg ll i = x;i;i -= lowbit(i))Inc(rt,b[i]);	
		return rt;
	}
}B;

inline void solve(ll l,ll r,vector<ll>v){
	if(l == r){
		for(rg ll i = 0;i < v.size();i++)ans[v[i]] = 2;
		return;
	}
	ll m = (l + r) >> 1;
	for(rg ll st = 1;st <= k;st++){
		B.reset();		
		for(rg ll i = m + 1;i <= r;i++){
			f[st][i] = B.query(a[i]);
			if(a[i] == st)Inc(f[st][i],1);
			B.ud(a[i],f[st][i]); 
		}
		for(rg ll i = m + 2;i <= r;i++)Inc(f[st][i],f[st][i-1]);
	}
	for(rg ll st = 1;st <= k;st++){
		B.reset();
		for(rg ll i = m;i >= l;i--){
			f[st][i] = B.query(k + 1 - a[i]);
			if(a[i] == st)Inc(f[st][i],1);
			B.ud(k + 1 - a[i],f[st][i]);
		}
		for(rg ll i = m - 1;i >= l;i--)Inc(f[st][i],f[st][i+1]);
	}
	for(rg ll i = l;i <= m;i++)Inc(f[1][i],1); //左半部分为空子串
	for(rg ll i = m + 1;i <= r;i++)Inc(f[k][i],1); //右半部分为空子串 
	vector<ll>vl,vr;
	vl.resize(0);
	vr.resize(0);
	for(rg ll i = 0;i < v.size();i++){
		ll id = v[i];
		if(R[id] <= m)vl.push_back(id);
		else if(L[id] > m)vr.push_back(id);
		else{
			for(rg ll j = k;j >= 1;j--)s[j] = Add(s[j+1],f[j][R[id]]);
			for(rg ll j = 1;j <= k;j++)Inc(ans[id],f[j][L[id]] * s[j] % mod);
		}
	}
	if(vl.size())solve(l,m,vl);
	if(vr.size())solve(m+1,r,vr); 
}

vector<ll>v;

int main(){
	n = read(),k = read();
	for(rg ll i = 1;i <= n;i++)a[i] = read();
	q = read();
	for(rg ll i = 1;i <= q;i++)L[i] = read(),R[i] = read();
	v.resize(0);
	for(rg ll i = 1;i <= q;i++)v.push_back(i);
	solve(1,n,v);
	for(rg ll i = 1;i <= q;i++)write(ans[i]),putchar('
');	
	return 0;
}
原文地址:https://www.cnblogs.com/xh092113/p/12283379.html