• The 2019 China Collegiate Programming Contest Harbin Site


    Contest Info


    [Practice Link](https://codeforces.com/gym/102394)
    Solved A B C D E F G H I J K L
    7/12 O - - - O O - - O O O Ø
    • O 在比赛中通过
    • Ø 赛后通过
    • ! 尝试了但是失败了
    • - 没有尝试

    Solutions


    A. Artful Paintings

    题意:
    (n)个小球,可以选择给一些小球染色,但是需要满足以下限制条件:

    • 对于第(i)个第一类限制,需要满足标号在([L_i, R_i])范围的小球被染色的个数需要大于等于(k_i)
    • 对于第(i)个第二类限制,需要满足标号在([L_i, R_i])范围外的小球被染色的个数需要大于等于(k_i)

    求最小的小球个数。

    思路:
    (S_i)表示前(i)个小球的被染色数量,如下建图:

    • (S_i - S_{i - 1} geq 0)
    • (S_i - S_{i - 1} leq 1)
    • 第一类限制:(S_{R_i} - S_{L_i - 1} geq k_i)
    • 第二类限制:(S_n - (S_{R_i} - S_{L_i - 1}) geq k_i)

    容易发现总的小球个数(S_n)具有单调性,二分,然后差分约束建图判断即可。

    代码:

    view code
    #include <bits/stdc++.h>
    using namespace std;
    using pII = pair <int, int>;
    #define fi first
    #define se second
    const int N = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    int n, M1, M2, Maxk;
    int dis[N], inq[N], cnt[N];
    int que[N], ql, qr;
    struct Edge {
    	int v, w;
    	Edge() {}
    	Edge(int v, int w): v(v), w(w) {}
    	bool operator < (const Edge &other) const {
    		return w < other.w;
    	}
    };
    vector <vector<Edge>> G;
    struct node {
    	int l, r, k;
    	void input() {
    		scanf("%d %d %d", &l, &r ,&k);
    		Maxk = max(Maxk, k);
    	}
    }q1[N], q2[N];
    
    inline void Init() {
    	G.clear(); G.resize(n + 1);
    	for (int i = 0; i <= n; ++i) {
    		inq[i] = 0, cnt[i] = 0, dis[i] = INF;
    	}
    }
    
    inline void addedge(int u, int v, int w) {
    	G[u].push_back(Edge(v, w));
    }
    
    bool SPFA(int x) {
    	for (int i = 0; i <= n; ++i) {
    		inq[i] = cnt[i] = 0;
    		dis[i] = INF;
    	}
    	dis[0] = 0;
    	inq[0] = 1;
    	queue <int> q;
    	q.push(0);
    	int limit = min(n, max(10, n / 2));
    	while (!q.empty()) {
    		int u = q.front(); q.pop();
    		inq[u] = 0;
    		for (auto &it : G[u]) {
    			int v = it.v, w = it.w;
    			if (dis[v] > dis[u] + w) {
    				dis[v] = dis[u] + w;
    				if (!inq[v]) {
    					inq[v] = 1;
    					q.push(v);
    					if (++cnt[v] > limit) return false;
    				}
    			}
    		}
    	}
    	return dis[n] == x;
    }
    
    bool check(int x) {
    	G.clear(); G.resize(n + 1);
    	for (int i = 1; i <= M1; ++i) {
    		int l = q1[i].l - 1, r = q1[i].r, k = q1[i].k;
    		addedge(r, l, -k);
    	}
    	for (int i = 1; i <= M2; ++i) {
    		int l = q2[i].l - 1, r = q2[i].r, k = q2[i].k;
    		addedge(l, r, x - k);
    	} 
    	for (int i = 1; i <= n; ++i) {
    		addedge(i, i - 1, 0);
    		addedge(i - 1, i, 1);
    	}
    	addedge(0, n, x);
    	addedge(n, 0, -x);
    	return SPFA(x);
    }
    
    int main() {   
    	int T;  
    	scanf("%d", &T);  
    	while (T--) {  
    		scanf("%d %d %d", &n, &M1, &M2); 
    	    Maxk = 0;	
    		for (int i = 1; i <= M1; ++i) q1[i].input(); 
    		for (int i = 1; i <= M2; ++i) q2[i].input(); 
    		int l = Maxk, r = n - 1, res = n;
    		while (r - l >= 0) {
    			int mid = (l + r) >> 1;
    			if (check(mid)) {
    				r = mid - 1;
    				res = mid;
    			} else {
    				l = mid + 1;
    			}
    		}
    		printf("%d
    ", res);
    	}
    	return 0;
    }
    

    E. Exchanging Gifts

    题意:
    (n)个序列,对于第(i)个序列,以以下两种方式之一给出:

    • (S_i = [q_1, q_2, cdots, q_k])
    • (S_i = S_x + S_y)

    最后求(S_n)的最大欢乐值,这个欢乐值是重新排列序列中的数,某个位置(i),如果重排列后的数和原始的数不一样,那么这个位置提供一个欢乐值。

    思路:
    容易发现序列的欢乐值和序列的总个数以及出现次数最多的数的个数有关。
    那么我们倒着做一遍,容易发现这是一个树结构,而对于直接给出的序列来说,他们是叶子结点,那么我们可以倒着标记一遍,这样可以标记出每个叶子结点出现多少次,然后暴力统计即可。

    代码:

    view code
    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    const int N = 1e6 + 10;
    struct Hash {
    	int a[N];
    	void init() { *a = 0; }
    	void add(int x) { a[++*a] = x; }
    	void gao() { sort(a + 1, a + 1 + *a); *a = unique(a + 1, a + 1 + *a) - a - 1; }
    	int get(int x) { return lower_bound(a + 1, a + 1 + *a, x) - a; }
    }hs;
    int n, m, x[N], y[N], op[N], sze[N]; 
    ll a[N], b[N];
    vector <vector<int>> vec;
    
    int main() {
    	int _T; scanf("%d", &_T);
    	while (_T--) {
    		scanf("%d", &n);
    		memset(b, 0, sizeof (b[0]) * (n + 10));
    		vec.clear(); vec.resize(n + 1);
    		hs.init();
    		for (int i = 1; i <= n; ++i) {
    			scanf("%d", op + i);
    			if (op[i] == 1) {
    				scanf("%d", sze + i);
    				vec[i].resize(sze[i]);
    				for (int j = 0; j < sze[i]; ++j) {
    					scanf("%d", &vec[i][j]);
    					hs.add(vec[i][j]);
    				}
    			} else {
    				scanf("%d%d", x + i, y + i);
    			}
    		}
    		hs.gao();
    		m = hs.a[0];
    		memset(a, 0, sizeof (a[0]) * (m + 10));
    		b[n] = 1;
    		for (int i = n; i >= 1; --i) {
    			if (b[i] == 0) continue;
    			if (op[i] == 1) {
    				for (int j = 0; j < sze[i]; ++j) {
    					vec[i][j] = hs.get(vec[i][j]);
    					a[vec[i][j]] += b[i];
    				}
    			} else {
    				b[x[i]] += b[i];
    				b[y[i]] += b[i];
    			}
    		}
    		ll tot = 0, Max = 0;
    		for (int i = 1; i <= m; ++i) {
    			tot += a[i];
    			Max = max(Max, a[i]);
    		}
    		ll res = 0;
    		if (Max <= tot / 2) res = tot;
    	    else res = (tot - Max) * 2;
    		printf("%lld
    ", res);	
    	}
    	return 0;
    }
    

    F. Fixing Banners

    签到。

    代码:

    view code
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e6 + 10;
    char s[N];
    int a[6][210]; 
    vector <int> id;
    
    bool ok() {
    	char *str = "harbin";
    	for (int i = 0; i < 6; ++i) {
    		if (a[id[i]][str[i]] == 0)
    			return false;
    	}
    	return true;
    }
    
    void gao() {
    	do {
    		if (ok()) {
    			puts("Yes");
    			return;
    		}
    	} while (next_permutation(id.begin(), id.end()));
    	puts("No");
    }
    
    int main() {
    	int _T; scanf("%d", &_T);
    	while (_T--) {
    		for (int i = 0; i < 6; ++i) {
    			a[i]['h'] = 0;
    			a[i]['a'] = 0;
    			a[i]['r'] = 0;
    			a[i]['b'] = 0;
    			a[i]['i'] = 0;
    			a[i]['n'] = 0;
    			scanf("%s", s + 1);
    			for (int j = 1, len = strlen(s + 1); j <= len; ++j) {
    				a[i][s[j]] = 1;
    			}
    		}
    		id.clear();
    		for (int i = 0; i < 6; ++i) id.push_back(i);
    		gao();
    	}
    	return 0;
    }
    

    I. Interesting Permutation

    题意:
    有一个排列(a_i),现在生成(f, g, h):

    • (forall i in [1, n], f_i = max{a_1, a_2, cdots, a_i})
    • (forall i in [1, n], g_i = min{a_1, a_2, cdots, a_i})
    • (forall i in [1, n], h_i = f_i - g_i)

    现在给出(h_i),求(a_i)的合法方案数。

    代码:

    view code
    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int MOD = 1e9 + 7;
    
    long long cntt[100000 + 10];
    int x[100000 + 10];
    
    int main() {
    	int T;
    	scanf("%d", &T);
    	cntt[0] = 1;
    	for (int i = 1; i <= 100000; ++i) cntt[i] = (cntt[i - 1] * 2) % MOD;
    	while (T--) {
    		int n;
    		int Max, flag;
    		long long ans, q = 1, t = 0, cnt;
    		scanf("%d", &n);
    		for (int i = 1; i <= n; ++i) scanf("%d", &x[i]);
    		if (n == 1) {
    			if (x[1] == 0) flag = 0;
    			else flag = 1;
    		}
    		else { 
    			if (x[1] == 0) {
    				flag = 0; ans = 0; Max = x[1]; q = 1; t = 0; cnt = 0;
    				for (int i = 2; i <= n; ++i) {
    					if (flag == 0) {
    						if (x[i] > Max) {
    							++t; cnt += (x[i] - Max - 1);
    							Max = x[i];
    							if (Max > n - 1) flag = 1;
    						}
    						else if (x[i] == Max) {
    							if (cnt > 0) {
    								q = (q * cnt) % MOD;
    								cnt--;		
    							}
    							else flag = 1;
    						}
    						else {
    							flag = 1;
    						}
    					}
    				}
    			}
    			else flag = 1;
    		}
    		//printf("f %d
    ", flag);
    		if (flag == 1) printf("0
    ");
    		else {
    			ans = cntt[t] * q % MOD;
    			printf("%lld
    ", ans);
    		}
    	}
    	return 0;
    }
    

    J. Justifying the Conjecture

    签到。

    代码:

    view code
    #include <bits/stdc++.h>
    using namespace std;
    
    int main() {
    	int _T; scanf("%d", &_T);
    	while (_T--) {
    		int n; scanf("%d", &n);
    		if (n < 6) puts("-1");
    		else if (n % 2 == 0) printf("%d %d
    ", 2, n - 2);
    		else printf("%d %d
    ", 3, n - 3);
    	}
    	return 0;
    }
    

    K. Keeping Rabbits

    代码:

    view code
    #include <bits/stdc++.h>
    
    using namespace std;
    
    using db = double;
    
    const int N = 1e5 + 10;
    
    int n, k;
    db w[N];
    
    int main() {
    	int T;
    	scanf("%d", &T);
    	while (T--) {
    		scanf("%d %d", &n, &k);
    		db sum = 0;
    		for (int i = 1; i <= n; ++i) {
    			scanf("%lf", w + i);
    			sum += w[i];
    		}
    		for (int i = 1; i <= n; ++i) {
    			w[i] += k * w[i] / sum;
    		}
    		for (int i = 1; i <= n; ++i) {
    			printf("%.10f%c", w[i], " 
    "[i == n]);
    		}
    	}
    	return 0;
    }
    

    L. LRU Algorithm

    题意:
    给出一个长度为(n)的操作序列,有(q)次询问,每次询问给出一个容量为(m)的cache,里面有一些元素,问这个操作序列使用(LRU)算法,并且cache容量在(m)的操作的过程中,
    是否有一步这个cache里面的元素和询问给出的是一致的。

    思路:
    预处理出所有询问的link-list的哈希值,然后暴力模拟LRU算法执行流程。
    每做一遍都处理出容量为(i)的cache当前的link-list哈希值,然后暴力枚举(q)个询问进行判断。
    不取模(Hash)比取模要快

    代码:

    view code
    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    using ull = unsigned long long;
    #define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0)
    void err() { cout << "33[39;0m" << endl; }
    template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << " "; err(args...); }
    const int N = 5e3 + 10;
    int n, m, q, a[N], used[N], b[N], len[N], ans[N]; 
    ull f[N], g[N], seed = 13331; 
    struct Hash {
    	constexpr static ull seed = 13331;
    	ull a[N];
    	void clear() { a[0] = 0; }
    	void add(int x, int y) { a[x] = a[x - 1] * seed + y; }
    	ull get(int x) { return a[x]; }
    }hs;
    
    int main() {
    	int _T; scanf("%d", &_T);
    	while (_T--) {
    		scanf("%d%d", &n, &q);
    		for (int i = 1; i <= n; ++i) scanf("%d", a + i), used[i] = 0; 
    		for (int i = 1; i <= q; ++i) {
    			scanf("%d", len + i);
    			hs.clear();
    			for (int j = 1; j <= len[i]; ++j) scanf("%d", b + j), hs.add(j, b[j]);
    			g[i] = hs.get(len[i]);
    			ans[i] = 0;
    			if (!g[i]) ans[i] = 1;
    		}
    		m = 0;
    	    for (int i = 1; i <= n; ++i) b[i] = 0;	
    		for (int i = 1; i <= n; ++i) {
    			int x = a[i];
    			if (used[x] == 0) {
    				b[++m] = x;
    				used[x] = m;	
    			} else {
    				for (int j = used[x]; j <= m; ++j) {
    					b[j] = b[j + 1];
    					used[b[j]] = j;
    				}
    				b[m] = x;
    				used[x] = m;
    			}
    			hs.clear();
    			int k = 0;
    			for (int j = m; j >= 1; --j) {
    				++k;
    				hs.add(k, b[j]);
    				f[k] = hs.get(k);
    			}
    			for (int j = m + 1; j <= n; ++j) {
    				++k;
    				hs.add(k, 0);
    				f[k] = hs.get(k);
    			}
    			for (int j = 1; j <= q; ++j) {
    				if (f[len[j]] == g[j]) 
    					ans[j] = 1;
    			}
    		}
    		for (int i = 1; i <= q; ++i)
    			puts(ans[i] ? "Yes" : "No");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java中的final关键字
    使用chrome浏览器调试时的搜索技巧
    查看“文件路径”&“在此处打开命令窗口”
    python安装 错误 “User installations are disabled via policy on the machine”
    Charles 激活入口以及账号密码
    大数据学习(一) | 初识 Hadoop
    Django基础3-数据库交互
    Django基础2
    Django基础使用1
    创建-Django创建启动
  • 原文地址:https://www.cnblogs.com/Dup4/p/11790255.html
Copyright © 2020-2023  润新知