zoukankan      html  css  js  c++  java
  • Codeforces Round #446 (Div. 2)

    Codeforces Round #446 (Div. 2)

    • 总体:rating涨了好多,虽然有部分是靠和一些大佬(例如 redbagHometown )交流的……希望下次能自己做出来2333

    A. Greed

    题意

    给你(n)个罐子,每个罐子都告诉了你它当前的饮料体积和它的总容积,问能否用两个罐子装下所有饮料((nle 100000)

    题解

    简单模拟即可,用两个最大的算一下,注意累和会爆(int)

    int a[100100], b[100100];
    long long sum = 0;
    int main () {
    	int n = read();
    	For (i, 1, n) {
    		a[i] = read();
    		sum += a[i];
    	}
    	For (i, 1, n)
    		b[i] = read();
    	sort (b + 1, b + 1 + n);
    	if (b[n] + b[n - 1] >= sum)
    		puts("YES");
    	else
    		puts("NO");
        return 0;
    }
    

    B. Wrath

    题意

    给你一个长度为(n)序列,每个点有个(l)值,会覆盖他前面(l)个点,问最后还剩多少个点没有被覆盖。((nle 100000)

    题解

    应该用差分简单做一下就行了,脑子一抽写了个线段树上去,幸亏过了2333(就当练手吧)

    代码

    const int N = 1e6 + 1e3;
    int sum[N << 2];
    
    #define lson o << 1, l, mid
    #define rson o << 1 | 1, mid + 1, r 
    void Build(int o, int l, int r) {
    	if (l == r) { sum[o] = 1; return ; }
    	int mid = (l + r) >> 1;
    	Build(lson); Build(rson);
    	sum[o] = sum[o << 1] + sum[o << 1 | 1];
    }
    
    int ul, ur;
    int lazy[N << 2];
    void push_down(int o) {
    	if (!lazy[o]) return;
    	lazy[o << 1] = lazy[o << 1 | 1] = 1; 
    	sum[o << 1] = sum[o << 1 | 1] = 0; lazy[o] = 0;	
    }
    
    void Update(int o, int l, int r) {
    	if (ul <= l && r <= ur) { lazy[o] = 1; sum[o] = 0; return ;}
    	push_down(o); int mid = (l + r) >> 1;
    	if (ul <= mid) Update(lson); if (ur > mid) Update(rson);
    	sum[o] = sum[o << 1] + sum[o << 1 | 1];
    }
    
    int main () {
    	int n = read();
    	Build(1, 1, n);
    	For (i, 1, n) {
    		int len = read();
    		if (i == 1) continue ;
    		if (!len) continue ;
    		ul = max(i - len, 1); ur = i - 1;
    		Update(1, 1, n);
    	}
    	printf ("%d
    ", sum[1]);
        return 0;
    }
    

    C. Pride

    题意

    给你一个长为(n)序列,你能进行一个操作,将相邻两个数中的一个替换为他们的(gcd),问至少进行多少次操作能把他们全部变成(1),如果不能完成输出(-1)。((nle 2000)

    题解

    这题一开始搞了我好久QAQ,想错了。其实就是先弄出一个(1),然后可以把其他所有的数字都变成(1),剩下的步数就是(n-1)。找那个步数,一定是一段连续区间(gcd=1)的情况,然后你用(O(n^2))去枚举一下,找到一个可行的最小长度。还需要特判一开始就有(1)的情况,不然会挂掉(我就惨遭hack了TAT,后来又hack了两个可怜鬼233)。

    代码

    const int N = 2010;
    int a[N], n, ans = 0x7f7f7f7f, res, now;
    
    int main () {
    	n = read();
    	res = n;
    	For (i, 1, n) {
    		a[i] = read();
    		if (a[i] == 1) -- res;	
    		now = __gcd(now, a[i]);
    	}
    	if (now != 1)
    		return puts("-1"), 0;
    	if (res != n)
    		return printf ("%d
    ", res), 0;
    	For (i, 1, n) {
    		int here = a[i], len = 0;
    		if (here == 1) {
    			ans = 0;
    			continue ;
    		}
    		Fordown (j, i - 1, 1) {
    			++ len;
    			here = __gcd(here, a[j]);
    			if (here == 1) {
    				chkmin(ans, len);
    				break;
    			}
    		}
    	}
    	printf ("%d
    ", ans + n - 1);
        return 0;
    }
    

    D. Gluttony

    题意

    给你一个长为(n)序列,其中每个数字都不相同,让你输出一个原序列的一个排列,使得他们中任意一个子集(不能为空集或者全集)的和都互不相同(就是相同位置上的数的和互不相同就行了)((nle 22)

    题解

    一开始不知道做法,redbag大佬讲出来了正解,就是将每一个数换成后一个比它大的数,最大的数换成最小的那一个,就行了。

    证明

    这个还是比较好证明的。

    考虑分两种情况讨论:

    1. 原子集没有最大的那个数:这就显然是个正确的,每个数都比之前的数要大,所以总和肯定要大;

    2. 原子集有最大的那个数:最大数改变后的值最整个里面最大的,然后你将这个子集去掉最大的那个数,剩下的变化量的和肯定要小于你最大值变为最小值的值,因为你之间肯定会有多余的空格(因为不能为全集)留着,所以肯定是可行的啦。

    代码

    int n, a[25];
    struct node {
    	int val, pos;
    	bool operator < (const node &rhs) const {
    		return val < rhs.val;
    	}
    };
    node lt[25];
    int ans[25];
    
    int main () {
    	n = read();
    	For (i, 1, n) {
    		lt[i].val = read();
    		lt[i].pos = i;
    	}
    	sort (lt + 1, lt + 1 + n);
    	For (i, 1, n) 
    		if (i != n)
    			ans[lt[i].pos] = lt[i + 1].val;
    		else 
    			ans[lt[i].pos] = lt[1].val;
    	For (i, 1, n)
    		printf ("%d ", ans[i]);
        return 0;
    }
    

    E. Envy

    终于来填远古巨坑了。

    题意

    给你一个有 (n) 个点 (m) 条边的带边权无向连通图。

    (q) 次询问,每次询问 (k) 条边是否能同时存在于 (MST) (最小生成树)中。(不要求在线回答)

    (n, m, q, sum k le 5 imes 10^5)

    题解

    首先要知道一个很显然的结论。

    就是在 (Kruskal)(MST) 过程中,我们能否把一条边 ((u, v, w)) 放入 (MST) 中,当且仅当 (<w) 的所有边联通后,(u, v) 仍然不连通。

    所以对于每次询问来说,边权不相同的边是互不影响的,我们可以对于这些边权互不相同的边单独考虑。

    相同 (w) 的如何考虑呢?首先 (<w) 的边全部加入,然后对于这些边按任意顺序加入的时候,不能存在 ((u, v)) 相连的情况。

    那么就可以得到一个离线算法了。把所有边权按权值排序,一条条加入。然后对于权值相同的同一询问的边,也逐个加入判断是否可行,最后利用可撤销并查集按秩合并的特性,把当前询问的边撤回就行了。

    最后复杂度就是 (O((m + sum k) log n)) 的。(挂询问用了 std :: map, set 有点慢。。)

    代码

    还是比较好写的。。

    #include <bits/stdc++.h>
    
    #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
    #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
    #define Set(a, v) memset(a, v, sizeof(a))
    #define Cpy(a, b) memcpy(a, b, sizeof(a))
    #define debug(x) cout << #x << ": " << (x) << endl
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define fir first
    #define sec second
    #define mp make_pair
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
    template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }
    
    inline int read() {
        int x(0), sgn(1); char ch(getchar());
        for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
        for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
        return x * sgn;
    }
    
    void File() {
    #ifdef zjp_shadow
    	freopen ("E.in", "r", stdin);
    	freopen ("E.out", "w", stdout);
    #endif
    }
    
    const int N = 5e5 + 1e3;
    
    struct Edge {
    	int u, v, w;
    } lt[N];
    
    int Hash[N], tot;
    
    struct Data {
    	int u, v, a, b;
    };
    
    namespace Union_Set {
    
    	int fa[N], height[N];
    
    	int find(int x) { return x == fa[x] ? x : find(fa[x]); }
    
    	Data stk[N]; int top;
    
    	inline bool Merge(int u, int v, bool flag) {
    		u = find(u); v = find(v); if (u == v) return false;
    		if (flag) stk[++ top] = (Data) {u, v, height[u], height[v]};
    		if (height[u] > height[v]) swap(u, v); fa[u] = v;
    		if (height[u] == height[v]) ++ height[v]; return true;
    	}
    
    	inline void Distract() {
    		Data cur = stk[top --];
    		height[fa[cur.u] = cur.u] = cur.a;
    		height[fa[cur.v] = cur.v] = cur.b;
    	}
    
    }
    
    bool ans[N];
    
    map<int, multiset<PII>> M[N];
    
    inline int find_pos(int x) {
    	return lower_bound(Hash + 1, Hash + tot + 1, x) - Hash;
    }
    
    int main () {
    
    	File();
    
    	int n = read(), m = read();
    
    	using namespace Union_Set;
    
    	For (i, 1, n) fa[i] = i;
    
    	For (i, 1, m) {
    		lt[i].u = read();
    		lt[i].v = read();
    		Hash[i] = lt[i].w = read();
    	}
    	sort(Hash + 1, Hash + m + 1);
    	tot = unique(Hash + 1, Hash + m + 1) - Hash - 1;
    
    	int q = read();
    	For (i, 1, m)
    		M[find_pos(lt[i].w)][q + 1].insert(mp(lt[i].u, lt[i].v));
    
    	For (i, 1, q) {
    		int k = read(); ans[i] = true;
    		For (j, 1, k) {
    			int id = read();
    			M[find_pos(lt[id].w)][i].insert(mp(lt[id].u, lt[id].v));
    		}
    	}
    
    	For (i, 1, tot) {
    		for (auto itm : M[i]) {
    			if (itm.fir != q + 1 && !ans[itm.fir]) continue ;
    			for (auto its : itm.sec)
    				ans[itm.fir] &= Merge(its.fir, its.sec, itm.fir <= q);
    			while (top) Distract();
    		}
    	}
    
    	For (i, 1, q)
    		puts(ans[i] ? "YES" : "NO");
    
    	return 0;
    
    }
    
  • 相关阅读:
    量化交易指标函数整理(持续更新)
    Python之基础练习代码
    根据缺口的模式选股买股票,python 学习代码
    凯利公式
    测试
    AngularJS开发经验
    Hibernate Tools插件的使用
    weblogic配置oracle数据源
    eclipse配置weblogic服务器
    java算法-数学之美二
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/7857739.html
Copyright © 2011-2022 走看看