zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    机器学习模型评估指标汇总
    Linux 搭建Hadoop集群错误锦集
    机器学习--聚类系列--DBSCAN算法
    机器学习--聚类系列--层次聚类
    机器学习--聚类系列--K-means算法
    数据分析--降维--LDA和PCA
    自然语言处理--Word2vec(一)
    自然语言处理--TF-IDF(关键词提取)
    Android学习笔记之BitmapFactory.Options实现图片资源的加载...
    Android学习笔记之蓝牙通信...
  • 原文地址:https://www.cnblogs.com/xh092113/p/12283379.html
Copyright © 2011-2022 走看看