Comet OJ - 2019国庆欢乐赛
Posted 163467wyj
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Comet OJ - 2019国庆欢乐赛相关的知识,希望对你有一定的参考价值。
https://www.cometoj.com/contest/68/problem/A
enmmmm 看到 许多的 爆 ll 的老故事
#include<bits/stdc++.h> using namespace std; int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int t,a,b,c,d; cin >> t; while(t--) { cin >> a >> b >> c >> d; if((a < 0 && c > 0) && (b < 0 && d > 0)) cout << "8 "; else if((a < 0 && c > 0) || (b < 0 && d > 0)) cout << "6 "; else cout << "5 "; } return 0; }
https://www.cometoj.com/contest/68/problem/B
从小到大排个序 a1 a2 a3 a4 a5, 如果 sum-a5 <= a5 那么全部都是有缘人 结果为 sum-a5
否则 结果为 sum/2, 相当于贪心每次拿最大的俩个数减1直到和小于2 可用数学归纳法证明
if sum == 2 || 3, result = sum/2
假设 sum > 3 && sum为偶数, sum -A(max) > A(max)
sum-A(max)-1 > A‘(max) 依旧成立, 故假设成立
#include<bits/stdc++.h> using namespace std; int main(){ int a[6] = {}; long long ans = 0; for(int i = 0; i < 5; i++) cin >> a[i], ans += a[i]; sort(a, a+5); if(ans-a[4] > a[4]) cout<< ans/2; else cout<< ans-a[4]; return 0; } /* 1 1 1 1 1 2 */
https://www.cometoj.com/contest/68/problem/C
直接枚举 左边的房子 用双指针求每个房子的对门右边房子数
也可以 用lower_bound 和 upper_bound 来缩减代码
/* 3 3 1 3 3 4 5 6 2 4 4 5 5 7 5 */ #include<bits/stdc++.h> using namespace std; #define _for(i,a,b) for(int i = (a); i < (b); i++) #define _rep(i,a,b) for(int i = (a); i <= (b); i++) #define l first #define r second const int N = 2e5+100; int n,m; pair<int, int > t[N], s[N]; int main(){ ios_base::sync_with_stdio(false); cin.tie(0); cin>> n >> m; _rep(i,1,n) cin >> t[i].l >> t[i].r; _rep(i,1,m) cin >> s[i].l >> s[i].r; int L = 1, R = 1, res = 0; _rep(i,1,n){ while(L <= m && s[L].r < t[i].l) L++; while(R <= m && s[R].l <= t[i].r) R++; res += R-L; } cout << res << endl; return 0; } //
#include<bits/stdc++.h> using namespace std; #define _for(i,a,b) for(int i = (a); i < (b); i++) #define _rep(i,a,b) for(int i = (a); i <= (b); i++) const int N = 2e5+100; int xl[N],xr[N],yl[N],yr[N]; int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n,m; cin >> n >> m; _rep(i,1,n) cin >> xl[i] >> xr[i]; _rep(i,1,m) cin >> yl[i] >> yr[i]; int res = 0; _rep(i,1,n) res += (upper_bound(yl+1, yl+m+1, xr[i])-yl) - (lower_bound(yr+1, yr+m+1, xl[i])-yr); cout << res << endl; return 0; }
https://www.cometoj.com/contest/68/problem/D1?problem_id=3936
n <= 1e5, 所以可以直接模拟 用前缀和 二分答案
// 1 // 5 3 2 7 // 1 1 1 // output 11 #include<bits/stdc++.h> using namespace std; #define _for(i,a,b) for(int i = (a); i < (b); i++) #define _rep(i,a,b) for(int i = (a); i <= (b); i++) #define ll long long const int N = 2e5+100; int a[N],pre[N]; int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int t; cin >> t; while(t--){ ll n,m,k,d,res = 0, sum = 0; cin >> n >> m >> k >> d; _rep(i,1,m) cin >> a[i], sum += a[i]; if(d >= n*sum) { cout << n*(m+k) << endl; continue;} sort(a+1, a+1+m); pre[0] = 0; _rep(i,1,m) pre[i] = pre[i-1]+a[i];// init 若是 +=,须得初始化 //_for(i,0,m) cout << pre[i] << " " ; cout << " "; _rep(i,0,n) {//枚举做完0~n张卷子剩下时间能做的题目 ll time = d - i*sum, score = i*(m+k), ans = 0; if(time < 0) break; ll l = 0, r = m; while(l <= r){ ll mid = (l+r)>>1; if(pre[mid]*(n-i) <= time) ans = mid, l = mid+1; else r = mid-1; } score += (n-i)*(ans) + (time-pre[ans]*(n-i))/a[ans+1]; res = max(res, score); } cout << res << endl; } return 0; }
https://www.cometoj.com/contest/68/problem/D2?problem_id=3937
由于 Q 5e4 n 1e9 故直接枚举n 不行, 但是 m 1e5 没变 所以可以试着枚举 m,
假设最优做到 第 P 道题时间耗尽, 有许多种做卷子的方法到 第P 道题目, 把这些方法的已经做了的卷子张数为一个区间
在这个区间的横轴中 得分的纵轴是一个一次函数(一条直线), 故极大值在两端 , 通过枚举题目算出相应的极值 取最大值即可(enmmmmmm 大体懂了, 具体代码细节还是不懂)
#include <bits/stdc++.h> using namespace std; const int Maxn = 500005; int m, k, res, T, a[Maxn]; long long n, ans, now, D; int main() { scanf("%d", &T); while (T--) { now = 0, ans = 0, res = 0; scanf("%lld%d%d%lld", &n, &m, &k, &D); for (int i = 1; i <= m; i++) scanf("%d", &a[i]), now += a[i]; sort(a + 1, a + 1 + m); for (int i = 1; i <= m; i++) { int all = min(n, D / now); ans = max(ans, all * (long long) (m + k - res) + min((n - all) * a[i], D - all * now) / a[i] + n * res); if (D - a[i] * n < 0) { ans = max(ans, D / a[i] + n * res); break; } if (i != m) { int tmp = ceil((D - a[i] * n) / (double) (now - a[i])); if (D - tmp * now >= 0) ans = max(ans, (long long) tmp * (m + k - res) + min(n * a[i], D - tmp * now) / a[i] + n * res); } now -= a[i]; D -= a[i] * n; res++; } printf("%lld ", ans); } return 0; }
https://www.cometoj.com/contest/68/problem/E?problem_id=3938
首先判断: 当 k 大于 n 时显然不成立, 其次 当 k 为 奇数时, 一个无向图中有 奇数个点的边为奇数也不成立(草稿纸上画了下发现是的, 具体没有严格证明)
当k成立时,考虑最多边数 所以直接无向图满边删最少边即可 若 n 为奇数 ,每个点连接的边都是n-1 (偶数条),只需要删去 k/2条边既可以产生k个点为奇数边
同理, 当 n 为偶数时, 每个点连接的边为n-1(奇数条), 只需要保留k个点不删边,删去 (n-k)/2条边既可产生 n-k个点为偶数边
略略有些拗口,不过在草纸上画一画便知
#include <bits/stdc++.h> using namespace std; #define _for(i,a,b) for(int i = (a); i < (b); i++) #define _rep(i,a,b) for(int i = (a); i <= (b); i++) int main(){ ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0); long long t,n,k; cin >> t; while(t--) { cin >> n >> k; //cout<< n <<k <<" "; if(k>n || k&1) cout<< "renrendoushijwj "; else { if(n&1) cout<< n*(n-1)/2-k/2 << endl; else cout << n*(n-1)/2-(n-k)/2 << endl; } } return 0; } /* 4 7 8 7 4 3 1 5 4 样例输出 1 renrendoushijwj 19 renrendoushijwj 8 */
以上是关于Comet OJ - 2019国庆欢乐赛的主要内容,如果未能解决你的问题,请参考以下文章
[CCPC-Wannafly & Comet OJ 夏季欢乐赛(2019)]飞行棋