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\n";
else if((a < 0 && c > 0) || (b < 0 && d > 0)) cout << "6\n";
else cout << "5\n";
}
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 << "\n";
_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\n", 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 <<" \n";
if(k>n || k&1) cout<< "renrendoushijwj\n";
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
*/
