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\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;
}
View Code

 

 

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
*/

 

posted @ 2019-10-16 20:59  163467  阅读(165)  评论(0编辑  收藏  举报