zoukankan      html  css  js  c++  java
  • CF1601E Phys Ed Online

    考虑一个贪心。

    我们一定采取的方案是

    \(b_i = \min_{j = i - k}^i a_j\)
    \(\sum a_l + b_{l + k} + \min_{i = 1}^2{b_{l + ik}} + \min_{i = 1}^3{b_{l + ik}}......\min_{i = 1}^t{b_{l + ik}}\)

    那么我们看出来可以只考虑同余系的关键点即可。

    但是我们发现我们不好计算答案。

    一个想要的考虑是扫描线。

    但是我们发现这样需要支持区间加,区间取 \(0\),区间加等差数列,单点查。
    然后我发现我不会区间加等差数列,所以只能考虑正解做法。

    考虑我们差分答案,记\(f_i\)为一直到结尾的答案,考虑倒序枚举\(i\),直接单调栈,其转移显然。

    那么\([l,r]\)答案应为\(f_i - f_p + b_p * {(r - p + 1)} + a_l\)
    \(p\)\([l,r]\)中最小值位置。

    考虑笛卡尔树上的\([l,r]\)的最小值位置即其两点\(LCA\)位置。

    那么复杂度为\(O(nlog{\frac{n}{k}} + q)\)

    较正解做法\(O(nlog + q)\) 效率应该差距不大。

    所以这里采用正解做法即ST表。

    #include<bits/stdc++.h>
    #define ll long long 
    #define N 600005
    #define int ll
    
    int n,q,k;
    
    std::pair<int,int> g[N][30];//ST表
    
    int lg[N],b[N];
    
    std::pair<int,int> get(int l,int r){
    	if(l > r)
    	return std::pair<int,int>(0,0);
    	int p = lg[r - l + 1];
    	return std::min(g[l][p],g[r - (1ll << p) + 1][p]);
    } 
    
    int stk[N],top,nxt[N],f[N];
    
    ll calc(int l,int r){
    	int p = get(l - k,r).second;
    	int tmp = g[p][0].first;
    	if(p == l - k)
    	p += k;
    	p = p + (r - p) % k;
    	return f[l] - f[p] + (r / k - p / k + 1) * b[p];
    }
    
    signed main(){
    	scanf("%d%d%d",&n,&q,&k);
    	lg[0] = -1;
    	for(int i = 1;i <= n;++i)
    	lg[i] = lg[i / 2] + 1;
    	for(int i = 1;i <= n;++i){
    		scanf("%d",&g[i][0].first);
    		g[i][0].second = i;
    	}
    	for(int j = 1;j <= 20;++j)
    	for(int i = 1;i + (1ll << j) - 1 <= n;++i)
    	g[i][j] = std::min(g[i][j - 1],g[i + (1ll << (j - 1))][j - 1]);
    	for(int i = k + 1;i <= n;++i)
    	b[i] = get(i - k,i).first;
    	for(int l = k + 1;l + k <= n && l <= 2 * k;++l){
    		int r = l + (n - l) / k * k;
    		top = 1;
    		for(int i = r;i >= l;i -= k){
    			while(top > 1 && b[i] <= b[stk[top]])
    			top -- ;
    			nxt[i] = stk[top];
    			f[i] = f[nxt[i]] + b[i] * (nxt[i] / k - i / k);
    			stk[++top] = i;
    		}
    	}
    	while(q -- ){
    		int l,r;
    		scanf("%d%d",&l,&r);
    		r = l + (r - l) / k * k;
    		std::cout<<(1ll * g[l][0].first + 1ll * (l + k <= r? calc(l + k,r) : 0))<<std::endl;
    	}
    }
    
  • 相关阅读:
    论频谱中负频率成分的物理意义(转载)
    VS2008的glaux库
    通过域名显示IP列表
    Shader errorX3205的解决
    Curl, Divergence, Circulation
    关于FIONREAD命令的作用
    Cairngorm的结构及开发使用(2)(转)
    结合Flex Builder和Flash CS4制作一个中国地图的应用(转)
    大型高并发高负载网站的系统架构(转)
    Cairngorm的结构及开发使用(4)(转)
  • 原文地址:https://www.cnblogs.com/dixiao/p/15628423.html
Copyright © 2011-2022 走看看