• 「LibreOJ β Round #3」绯色 IOI(危机)(单调栈+动态规划+复杂度分析)


    https://loj.ac/problem/522

    第一个性质是在告诉我们这是个DAG。

    所以暴力的做法就是设(f[i])表示(i)结尾的最大答案,去枚举能够到达(i)(j),转移即可,转移顺序可以按半径从大到小。

    注意到那个转移式显然是不可优化的,也就是我们只能暴力枚举(j),事实上对于每个(i)可能的(j)只有(O(log))个。

    证明:

    首先对于(forall d(x,y),d(x,y)<=2log~r)
    结合“(d(x,y)=3,则x能直接引爆y的性质)”,发现每两次连续引爆半径会缩小一半。

    再考虑对于一个点(i),对于一个确切的(x),它左边的(d(j,i)=x)(j)是唯一的,这个可以假设有两个,发现那两个一定冲突。

    所以能引爆(i)(j)不超过(4log~r)个,那么接下来只要快速找出这些(j)就好了。

    一种方法是用扫描线+set暴力维护,时间复杂度(O(n*log~n*log~r)),可能会TLE。

    题解法:对每个点(i),找到左边右边的(d(j,i)=2)的两个(j),这个可以通过做两遍单调栈+二分得到。

    然后每次dfs去找到所以能引爆(i)(j),时间复杂度:(O(n~log~r))

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int mo = 998244353;
    
    const int N = 3e5 + 5;
    
    int n;
    ll a[N], b[N], c[N];
    int d[N];
    
    int cmp(int x, int y) {
    	return a[x] < a[y];
    }
    
    ll w[N];
    int z[N], z0;
    int fa[N][2];
    
    int cmp2(int x, int y) {
    	return b[x] > b[y];
    }
    
    int t, bz[N];
    ll f[N];
    
    void dg(int x) {
    	if(!x || bz[x] == t) return;
    	bz[x] = t;
    	if(x != t) f[t] = max(f[t], f[x] + ((c[t] ^ c[x]) + c[t] * c[x]) % mo);
    	dg(fa[x][0]); dg(fa[x][1]);
    }
    
    int main() {
    	scanf("%d", &n);
    	fo(i, 1, n) scanf("%lld", &a[i]);
    	fo(i, 1, n) scanf("%lld", &b[i]);
    	fo(i, 1, n) scanf("%lld", &c[i]);
    	fo(i, 1, n) d[i] = i;
    	sort(d + 1, d + n + 1, cmp);
    	fo(i, 1, n) w[i] = a[i] + b[i];
    	fo(i, 1, n) {
    		int x = d[i];
    		int as = 0;
    		for(int l = 1, r = z0; l <= r; ) {
    			int m = l + r >> 1;
    			if(w[z[m]] >= a[x]) as = m, l = m + 1; else r = m - 1;
    		}
    		fa[x][0] = z[as];
    		while(z0 > 0 && w[z[z0]] <= w[x]) z0 --;
    		z[++ z0] = x;
    	}
    	fo(i, 1, n) w[i] = a[i] - b[i];
    	z0 = 0;
    	fd(i, n, 1) {
    		int x = d[i];
    		int as = 0;
    		for(int l = 1, r = z0; l <= r; ) {
    			int m = l + r >> 1;
    			if(w[z[m]] <= a[x]) as = m, l = m + 1; else r = m - 1;
    		}
    		fa[x][1] = z[as];
    		while(z0 > 0 && w[z[z0]] >= w[x]) z0 --;
    		z[++ z0] = x;
    	}
    	sort(d + 1, d + n + 1, cmp2);
    	fo(i, 1, n) {
    		t = d[i], dg(t);
    	}
    	fo(i, 1, n) pp("%lld
    ", f[i]);
    }
    
  • 相关阅读:
    LRU
    c++ 在临时变量上使用const引用
    剑指 Offer 13. 机器人的运动范围
    C++之对象包含与成员函数不兼容的类型限定符
    C#獲取指定格式日期
    在ORACLE產生001,002的流水號
    ASP.NET中DataList数字分页代码
    生成條碼標的Class
    sql 将横的记录显示为竖的记录 max(case when CASE ltrim(ps.SIZE) WHEN '4.5' THEN ps.PairPerCarton END is null then null else ps.PairPerCarton end ) AS [4.5]
    为什么margin-top值不是作用域父元素
  • 原文地址:https://www.cnblogs.com/coldchair/p/12751307.html
Copyright © 2020-2023  润新知