• Educational Codeforces Round 126 (Rated for Div. 2)


    这场 vp 爆了,属于是被干碎了(怎么回归文化课两周就退步那么多)。

    CF1661A Array Balancing

    每个位置与下一个位置之间产生的贡献完全独立,因此对于每个位置讨论最小贡献就好了。

    CF1661B Getting Zero

    模数是 \(2\) 的幂次,因此答案最多在 \(\log\) 级别,因此最多使用少量 \(1\) 操作,一旦开始 \(2\) 操作后进行一操作必然不优,枚举 \(1\) 操作次数即可。

    CF1661C Water the Trees

    我讨厌分讨。 /dk

    显然最后高度不会超过 \(\max h + 1\),因此讨论最高高度是 \(\max h\)\(\max h + 1\) 的两种情况哪种优秀。

    因此确定最高高度后可以知道至少需要多少次加 \(1\) 操作和在此情况下要用多少加 \(2\) 操作。

    显然我们不能将一个加 \(2\) 拆为两个加 \(1\) ,但可以将两个 \(1\) 变为 \(2\) ,讨论一下才能使两种操作平均即使用天数最少。

    恶恶心心。

    read(n);
    		int mx = 0;
    		for (int i = 1; i <= n; ++i) read(h[i]) , mx = max(mx , h[i]);
    		LL ans = 1e18;
    		LL od = 0 , ev = 0;
    		for (int i = 1; i <= n; ++i) {
    			if((mx - h[i]) & 1) od ++;
    			ev += (mx - h[i]) / 2;
    		}
    		if(od > ev) {
    			ans = min(ans , od * 2 - 1);
    		}
    		else {
    			LL k = ev - od;
    			ev -= k / 3;
    			ans = min(ans , ev * 2 - (k % 3 == 2));
    		}
    		
    		mx ++;
    		od = 0 , ev = 0;
    		for (int i = 1; i <= n; ++i) {
    			if((mx - h[i]) & 1) od ++;
    			ev += (mx - h[i]) / 2;
    		}
    		if(od > ev) {
    			ans = min(ans , od * 2 - 1);
    		}
    		else {
    			LL k = ev - od;
    			ev -= k / 3;
    			ans = min(ans , ev * 2 - (k % 3 == 2));
    		}
    		write(ans);
    

    CF1661D Progressions Covering

    从后往前考虑,注意到最后一个元素只在一种情况下能增加,则一直加直到满足条件,然后这个操作就没有使用的必要了,因为一定不优。

    因此归约成 \(n - 1\) 的情况,树状数组模拟一下就好了。

    CF1661E Narrow Components

    仔细分析,发现从中间截取一段,最多只有断口的联通块受到影响,讨论一下是否会裂成两个连通块。

    首先通过减去完全不在区间内的连通块,我们可以知道答案至少为多少。

    然后检查断口,如果为 101 且两个 1 属于同一个连通块则检查在区间内能否被联通,具体地,找到他之后的第一个不是 101 的列,如果该列存在 0 则必然这个连通块被裂开了。

    特别地,特判区间内全是 101 的情况。

    const int MAXN = 5e5 + 5;
    
    int n;
    char s[3][MAXN];
    int id[3][MAXN] , cnt , nxt[MAXN] , las[MAXN];
    int sl[MAXN] , sr[MAXN];
    
    int R , L;
    void dfs(int x , int y) {
    	if(id[x][y] || s[x][y] == '0') return;
    	id[x][y] = cnt;
    	R = max(R , y) , L = min(L , y);
    	if(x > 0) dfs(x - 1 , y);
    	if(x < 2) dfs(x + 1 , y);
    	if(y > 1) dfs(x , y - 1);
    	if(y < n) dfs(x , y + 1); 
    }
    
    bool check(int x) {
    	return (s[0][x] == '0') || (s[1][x] == '0') || (s[2][x] == '0');
    }
    
    int main() {
    	read(n);
    	for (int i = 0; i < 3; ++i) scanf("%s" , s[i] + 1);
    	
    	for (int i = 0; i < 3; ++i) for (int j = 1; j <= n; ++j) if(s[i][j] == '1' && !id[i][j]) {
    		++cnt;R = 0 , L = n + 1;
    		dfs(i , j);
    		sl[R] ++ , sr[L] ++;
    	}
    	
    	for (int j = 1; j <= n; ++j) {
    		if(s[0][j] == '1' && s[1][j] == '0' && s[2][j] == '1') las[j] = las[j - 1];
    		else las[j] = j;
    		sl[j] += sl[j - 1];
    	}
    	nxt[n + 1] = n + 1;
    	for (int j = n; j >= 1; --j) {
    		if(s[0][j] == '1' && s[1][j] == '0' && s[2][j] == '1') nxt[j] = nxt[j + 1];
    		else nxt[j] = j;
    		sr[j] += sr[j + 1];
    	}
    	
    	int Q;read(Q);
    	while(Q -- > 0) {
    		int l , r;
    		read(l),read(r);
    		int ans = cnt - sl[l - 1] - sr[r + 1];
    		if((s[0][l] == '1' && s[1][l] == '0' && s[2][l] == '1') && nxt[l] > r) {
    			write(2);
    			continue;
    		}
    		if((s[0][l] == '1' && s[1][l] == '0' && s[2][l] == '1' && id[0][l] == id[2][l]) && check(nxt[l])) ans ++;
    		if((s[0][r] == '1' && s[1][r] == '0' && s[2][r] == '1' && id[0][r] == id[2][r]) && check(las[r])) ans ++;
    		write(ans);
    	}
    	
    	return 0;
    }
    

    CF1661F Teleporters

    一眼发现与分段有关系,由均值不等式得知对一段添加 \(x\) 个点怎样加最优。

    注意到一个段里的点随着越来越多,对当前答案的优化程度会越来越少。

    得到一个与答案大小相关的做法,即每次选择对答案变化量最大的一段添加一个点,直到答案小于 \(m\)

    很明显很不优秀,注意到可以二分最低添加一个点的减量,把每一段都一直加点直到减量小于二分值。

    加点数量也可以二分。

    最后算出答案,其中最低减量为 \(d\) ,但是可能有些减量为 \(d\) 的加点是不用实施的,因此减去这些点就好了。

    略微卡常。

    inline LL f(LL d , LL t) {
    	if(!t) return 5e18;
    	LL k = d / t , num = d % t;
    	return k * k * t + (k * 2 + 1) * num;
    }
     
    inline pll check(LL x) {
    	pll res = mp(0 , 0);
    	for (int i = 1; i <= n; ++i) {
    		LL d = a[i] - a[i - 1];
    		int l = 0 , r = d;
    		pll now = mp(m + 1 , m + 1);
    		while(l <= r) {
    			int mid = (l + r) >> 1;
    			LL tmp = f(d , mid + 1);
    			LL cur = f(d , mid) - tmp;
    			if(cur >= x) l = mid + 1 , now = mp(tmp , mid);
    			else r = mid - 1;
    		}
    		res.fs += now.fs , res.sc += now.sc;
    		if(res.fs > m) return res;
    	} 
    	return res;
    }
     
    int main() {
    //	freopen("1.in" , "r" , stdin);
    	read(n);
    	for (int i = 1; i <= n; ++i) read(a[i]);
    	read(m);
    	LL l = 0 , r = m , now = 0;
    	pll res = mp(0 , 0);
    	while(l <= r) {
    		LL mid = (l + r) >> 1;
    		pll cur = check(mid);
    		if(cur.fs <= m) res = cur , now = mid , l = mid + 1;
    		else r = mid - 1;
    	}
    	
    	res.sc -= (m - res.fs) / now;
    	
    	write(res.sc);
    	
    	return 0;
    }
    
  • 相关阅读:
    安装SQLServer2000提示“无法验证产品密钥”的解决方法
    【转】SQL Server数据库开发的二十一条军规
    Asp.Net实现FORM认证的一些使用技巧
    记住window.open的用法
    VS2005的关于母版页嵌套的一个小技巧
    一种写法的区别
    问个关于VS使用上的问题
    Server.MapPath方法的应用方法
    一个关于重定向的问题研究,应该具有实用性
    象WORD一样,双击.doc的文件就自动打开WORD并编辑该文件(转)
  • 原文地址:https://www.cnblogs.com/Reanap/p/16251002.html
Copyright © 2020-2023  润新知