zoukankan      html  css  js  c++  java
  • Codeforces Educational Round 33 题解

    题目链接   Codeforces Educational Round 33

    Problem A

    按照题目模拟,中间发现不对就直接输出NO。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define MP		make_pair
    #define fi		first
    #define se		second
    
    
    typedef long long LL;
    
    int a, b, c, n;
    
    
    int main(){
    	
    	a = 1, b = 2, c = 3;
    	scanf("%d", &n);
    	rep(i, 1, n){
    		int x;
    		scanf("%d", &x);
    		if (x != a && x != b) return 0 * puts("NO");
    		if (x == a) swap(b, c); else swap(a, c);
    	}
    
    	puts("YES");	
    	return 0;
    }

    Problem B

    打表然后塞到set里面,然后查找一下。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define MP		make_pair
    #define fi		first
    #define se		second
    
    
    typedef long long LL;
    
    int c[20];
    int a[100010];
    int n;
    int cnt, et;
    set <int> s;
    
    
    int main(){
    
    	rep(i, 1, 10){
    		int a = (1 << i) - 1;
    		int b = (1 << (i - 1));
    		s.insert(a * b);
    	}
    
    	rep(i, 1, et) printf("%d
    ", c[i]);
    
    	scanf("%d", &n);
    	rep(i, 1, n) if (n % i == 0) a[++cnt] = i;
    	dec(i, cnt, 1) if (s.count(a[i])) return 0 * printf("%d
    ", a[i]);;
    	return 0;
    }

    Problem C

    在每个连通块里面找个权值最小的然后加起来即可。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define MP		make_pair
    #define fi		first
    #define se		second
    
    
    typedef long long LL;
    
    const int N = 1e6 + 10;
    
    
    LL  a[N];
    LL  now;
    LL  ans = 0;
    int vis[N];
    vector <int> v[N];
    int n, m;
    
    void dfs(int x){
    	vis[x] = 1;
    	now = min(now, a[x]);
    	for (auto u : v[x]){
    		if (!vis[u]) dfs(u);
    	}
    }
    	
    
    int main(){
    
    	scanf("%d%d", &n, &m);
    	rep(i, 1, n) scanf("%lld", a + i);
    
    	rep(i, 1, m){
    		int x, y;
    		scanf("%d%d", &x, &y);
    		v[x].push_back(y);
    		v[y].push_back(x);
    	}
    
    	rep(i, 1, n) if (!vis[i]){
    		now = 1e10;
    		dfs(i);
    		ans += now;
    	}
    
    	printf("%lld
    ", ans);
    	return 0;
    }

    Problem D

    考虑每一天的时候,记录min和max,分别表示钱的下限值和上限值。

    如果min都超过d了那肯定不行了,输出-1。

    check的时候根据mx是否非负来决定是否更新答案。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    int n, d;
    int x;
    int mi = 0, mx = 0;
    int ans;
    
    
    int main(){
    
    	scanf("%d%d", &n, &d);
    	rep(i, 1, n){
    		scanf("%d", &x);
    		if (x){
    			mi += x, mx += x;
    			if (mi > d) return 0 * puts("-1");
    			mx = min(mx, d);
    		}
    
    		else{
    			if (mx >= 0) mi = max(mi, 0);
    			else ++ans, mx = d, mi = 0;
    		}
    	}
    
    	printf("%d
    ", ans);
    	return 0;
    }

    Problem E

    首先来个预处理,把所有的数的质因子以及指数求出来。

    然后对于每一个质因子c,找到他的指数d。

    转化成盒子里面放小球的问题。

    (盒子不同,小球相同,允许空盒子的情况)

    那么当前质因子c对答案的贡献即为$C(y + d - 1, d)$

    由于各质因子之间是独立的,所以直接相乘即可。

    最后还有-1的情况,对整个ans乘上$2^{y - 1}$即可。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define MP		make_pair
    #define fi		first
    #define se		second
    
    
    typedef long long LL;
    typedef pair <int, int> PII;
    
    const int N   = 2e6 + 10;
    const int mod = 1e9 + 7;
    
    int fac[N];
    int c[N];
    int val[N];
    int ret, q, x, y;
    int inv[N];
    vector <PII> pri[N];
    
    
    
    inline int Pow(int a, int b, int mod){
            int ret = 1;
            for (; b; b >>= 1, a = 1ll * a * a % mod) if (b & 1) ret = 1ll * ret * a % mod;
            return ret;
    }
    
    inline int C(int n, int k){ return 1ll * fac[n] * inv[k] % mod * inv[n - k] % mod; }
    
    
    void init(){
    	fac[0] = 1;
    	rep(i, 1, 2e6 + 3) fac[i] = 1ll * fac[i - 1] * i % mod;
    	rep(i, 0, 2e6 + 3) inv[i] = Pow(fac[i], mod - 2, mod);
    	rep(i, 1, 1e6 + 3) val[i] = i;
    	rep(i, 2, 1e6 + 3) if (!c[i]){
    		for (int j = i * 2; j <= 1e6 + 3; j += i){
    			c[j] = 1;
    	 		int cnt = 0;
    			while (val[j] % i == 0) val[j] /= i, ++cnt;
    			pri[j].push_back(MP(i, cnt));
    		}
    	}
    
    	rep(i, 2, 1e6 + 3) if (val[i] > 1)
    		pri[i].push_back(MP(i, 1));
    }
    
    
    
    int main(){
    
    	init();
    	scanf("%d", &q);
    	while (q--){
    		int x, y;
    		scanf("%d%d", &x, &y);
    		ret = Pow(2, y - 1, mod);
    		for (auto u : pri[x]){
    			int d = u.se;
    			ret = 1ll * ret * C(y + d - 1, d) % mod;
    		}
    		printf("%d
    ", ret);
    	}
    
    	return 0;
    }

    Problem F

    对于每一个结点,维护以他为根的子树中深度在[l, r]范围内的所有点的权值的最小值。

    一开始每个点在空树的基础上在自己这个深度插入自己的权值。

    每个点的插入复杂度为$O(logn)$,因为要开$logn$棵线段树。

    然后dfs一遍,做$n$次线段树合并即可。

    查询的时候对询问的距离$d$加上当前结点的深度$deep$,这样就构成了一个询问区间$[1, d + deep]$。

    为什么左端点是$1$呢,因为当前结点代表的线段树在$[1, deep - 1]$内都没有信息,那么$[1, d + deep]$就可以等效题目的询问区间。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define MP		make_pair
    #define fi		first
    #define se		second
    
    typedef long long LL;
    
    const int N = 1e5 + 10;
    const int M = 2e7 + 10;
    
    int father[N], deep[N];
    int n, r;
    vector <int> v[N];
    int a[N];
    int t[M], ls[M], rs[M];
    int tot = 0;
    int val[M];
    int m;
    int ans;
    
    
    void dfs(int x, int fa, int dep){
    	deep[x] = dep;
    	father[x] = fa;
    	for (auto u : v[x]){
    		if (u == fa) continue;
    		dfs(u, x, dep + 1);
    	}
    }
    
    int ins(int x, int a, int b, int c, int p){
    	int y = ++tot;
    	val[y] = min(val[x], p);
    	if (a == b) return y;
    	int mid = (a + b) >> 1;
    	if (c <= mid) ls[y] = ins(ls[x], a, mid, c, p), rs[y] = rs[x];
    	else ls[y] = ls[x], rs[y] = ins(rs[x], mid + 1, b, c, p);
    	return y;
    }
    
    int ask(int x, int a, int b, int d){
    	if (b <= d) return val[x];
    	int mid = (a + b) >> 1, t = ask(ls[x], a, mid, d);
    	if (d > mid) t = min(t, ask(rs[x], mid + 1, b, d));
    	return t;
    }
    
    int merge1(int x, int y, int a, int b){
    	if (!x || !y) return x + y;
    	int z = ++tot;
    	val[z] = min(val[x], val[y]);
    	if (a == b) return z;
    	int mid = (a + b) >> 1;
    	ls[z] = merge1(ls[x], ls[y], a, mid);
    	rs[z] = merge1(rs[x], rs[y], mid + 1, b);
    	return z;
    }
    
    void work(int x, int fa){
    	for (auto u : v[x]){ if (u == fa) continue; work(u, x); }
    	for (auto u : v[x]){
    		if (u == fa) continue;
    		t[x] = merge1(t[x], t[u], 1, n);
    	}
    }
    
    int main(){
    
    	scanf("%d%d", &n, &r);
    	rep(i, 1, n) scanf("%d", a + i);
    	rep(i, 0, 2e7) val[i] = 2147000000;
    
    	rep(i, 2, n){
    		int x, y;
    		scanf("%d%d", &x, &y);
    		v[x].push_back(y);
    		v[y].push_back(x);
    	}
    
    	dfs(r, 0, 1);
    	rep(i, 1, n) t[i] = ins(0, 1, n, deep[i], a[i]);
    	work(r, 0);
    	ans = 0;
    	scanf("%d", &m);
    	while (m--){
    		int x, y;
    		scanf("%d%d", &x, &y);
    		x = ((x + ans) % n) + 1;
    		y = ((y + ans) % n);
    		y += deep[x];
    		if (y > n) y = n;
    		printf("%d
    ", ans = ask(t[x], 1, n, y));
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    vue开发(一)安装
    Ubuntu18.04安装mysql
    使用.NET Framework开发IIS 7.0模块和处理程序拦截请求实现跳转
    Mysql 清空数据后,释放硬盘文件
    依赖注入
    ubuntu 上开发.netcore
    使用python获取微医数据
    Mysql查询某字段重复值并删除重复值
    使用pyinstaller 打包python程序
    堆(heap)和栈(stack)、内存泄漏(memory leak)和内存溢出
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/7913947.html
Copyright © 2011-2022 走看看