ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-04-22 12:53:56  阅读:350  来源: 互联网

标签:LibreOJ int dg 复杂度 IOI lld z0 ll fo


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("\n")
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\n", f[i]);
}

标签:LibreOJ,int,dg,复杂度,IOI,lld,z0,ll,fo
来源: https://www.cnblogs.com/coldchair/p/12751307.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有