zoukankan      html  css  js  c++  java
  • Codeforces Round #645 (Div. 2) A

    题目链接


    (A. Park Lighting)

    (Description:)
      给出 (n imes m) 的矩阵,你需要用灯照亮矩阵的每个单元格,灯只能摆放在单元格的边框上(具体参考原题里的图),如果某个单元格的边框上有一盏灯,那么该单元格将被照亮,问最少需要多少个单元格?
    (Solution:)
      贪心即可。
    (Code:)

    /*
    @Author: nonameless
    @Date:   2020-05-27 15:54:25
    @Email:  2835391726@qq.com
    @Blog:   https://www.cnblogs.com/nonameless/
    */
    #include <bits/stdc++.h>
    #define x first
    #define y second
    #define all(x) x.begin(), x.end()
    #define sz(x) (int)x.size()
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> PII;
    typedef pair<ll, ll> PLL;
    const double PI  = acos(-1.0);
    const double eps = 1e-8;
    const int INF = 0x3f3f3f3f;
    const ll LNF  = 0x3f3f3f3f3f3f;
    inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
    inline ll  gcd(ll  a, ll  b) { return b ? gcd(b, a % b) : a; }
    inline int lcm(int a, int b) { return a * b / gcd(a, b); }
    
    
    int main(){
    
        int t; cin >> t;
        while(t --){
            int n, m; cin >> n >> m;
            int ans = 0;
            ans = n / 2 * m;
            if(n & 1){
                ans += m / 2 + (m % 2);
            }
            cout << ans << endl;
        }
        return 0;
    }
    
    


    (B. Maria Breaks the Self-isolation)

    (Description:)
      给定长度为 (n) 的数组 (a),现有一个院子,院子里最初有一个人,那么他要叫其他 (n) 个人来,每个人来的条件是 (a_i leq) 院子里的人 (+) 和他一起来的人的个数(可以一次叫多个人来),问最后院子里最多有几个人?
    (Solution:)
      给 (a) 排序,从小到大遍历一边,如果对于 (i) 来说,他不满足条件,那么我们就让他等待(即等后面的人一起去),直到遇到 (j) 满足 (a_j leq cnt + ans)(cnt) 是当前等待的人,(ans) 是当前院子里的人数。此时 (j) 是满足条件的,那么由于 (a_i leq a_j),那么 (i) 显然也是符合条件的。
    (Code:)

    /*
    @Author: nonameless
    @Date:   2020-05-27 16:00:38
    @Email:  2835391726@qq.com
    @Blog:   https://www.cnblogs.com/nonameless/
    */
    #include <bits/stdc++.h>
    #define x first
    #define y second
    #define all(x) x.begin(), x.end()
    #define sz(x) (int)x.size()
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> PII;
    typedef pair<ll, ll> PLL;
    const double PI  = acos(-1.0);
    const double eps = 1e-8;
    const int INF = 0x3f3f3f3f;
    const ll LNF  = 0x3f3f3f3f3f3f;
    inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
    inline ll  gcd(ll  a, ll  b) { return b ? gcd(b, a % b) : a; }
    inline int lcm(int a, int b) { return a * b / gcd(a, b); }
    
    
    int main(){
    
        int t; cin>> t;
        while(t --){
            vector<int> vec;
            int n; cin >> n;
            for(int i = 1; i <= n; i ++){
                int x; scanf("%d", &x);
                vec.pb(x);
            }
            sort(all(vec));
            int ans = 1, cnt = 0; // cnt 是未进去的
            for(int i = 0; i < sz(vec); i ++){
                if(vec[i] <= ans + cnt){
                    ans += cnt + 1;
                    cnt = 0; // 全部进去
                } else cnt ++; // 等待的人的个数 ++
            } 
    
            cout << ans << endl;
    
        }
        return 0;
    }
    
    


    (C. Celex Update)

    (Description:)
      给定如下矩阵:

      给定 ((x_1,y_1),(x_2,y_2)),从 ((x_1,y_1)) 走到 ((x_2,y_2)),可以向右和向下走,显然有多条路径,对于一条路径上的各个数字,我们可以求出他的和,问有几个不同的和?
    (Solution:)
      最开始光凭脑袋想一点思路没有,然后动手模拟了几遍,就发现了规律:

    1. 先一直向右走,再一直向下走,就得到了最小值
    2. 先一直向下走,再一直向右走,就得到了最大值
      那么我们用最大值 (-) 最小值 (+1) 就是答案了。那么我们要如何求到了,通过观察可以发现对于上面两种方式走的每一步,都会产生差值:(0,1,2,3,...,x,x,x,x...,x-1,x-2,...,0)。该数列的和 (=) 最大值减去最小值,设 (t) 是我们一共走的步数,那么 (t = x_2-x_1+y_2-y_1),那么由 (0)(x-1)(x-1)(0) 一共有 (2x) 个数,即还剩下 (t - 2x)(x),通过观察可以发现 (x = min(x_2-x_1,y_2-y_1)),那么设 (a = min(x_2-x_1,y_2-y_1); b = max(x_2-x_1,y_2-y_1)),即 (x = a),且 (t = a + b),那么总和就为:

    [ 2 imes frac{(0+a-1) imes a}{2} + (a+b-2a) imes a = a imes b ]

      最后别忘了 (+1)

    (Code:)

    /*
    @Author: nonameless
    @Date:   2020-05-27 20:14:51
    @Email:  2835391726@qq.com
    @Blog:   https://www.cnblogs.com/nonameless/
    */
    #include <bits/stdc++.h>
    #define x first
    #define y second
    #define all(x) x.begin(), x.end()
    #define sz(x) (int)x.size()
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> PII;
    typedef pair<ll, ll> PLL;
    const double PI  = acos(-1.0);
    const double eps = 1e-8;
    const int INF = 0x3f3f3f3f;
    const ll LNF  = 0x3f3f3f3f3f3f;
    inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
    inline ll  gcd(ll  a, ll  b) { return b ? gcd(b, a % b) : a; }
    inline int lcm(int a, int b) { return a * b / gcd(a, b); }
    
    
    int main(){
    
        int t; cin >> t;
        while(t --){
            ll x1, x2, y1, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            cout << (x2 - x1) * (y2 - y1) + 1 << endl;
        }
        return 0;
    }
    
    


    (D. The Best Vacation)

    (Description:)
      一年有 (n) 个月,每个月有 (d[i]) 天,其中,第 (j) 的价值为 (j),问连续 (x) 天的价值最大可以是多少?(可以跨年)
    (Solution:)
      要想价值最大,那我们显然是要选择到 (d[i]) 这一天的,即月尾,那么月尾是放在中间还是最后一天呢?对于放在中间,后续还有一系列的数,但显然价值都是很小的,因为又是从 (1) 开始的了,所以我们考虑把月尾放在最后一天,然后我们遍历每个月即可。
    (Code:)

    /*
    @Author: nonameless
    @Date:   2020-05-28 14:27:16
    @Email:  2835391726@qq.com
    @Blog:   https://www.cnblogs.com/nonameless/
    */
    #include <bits/stdc++.h>
    #define x first
    #define y second
    #define all(x) x.begin(), x.end()
    #define sz(x) (int)x.size()
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> PII;
    typedef pair<ll, ll> PLL;
    const double PI  = acos(-1.0);
    const double eps = 1e-8;
    const int INF = 0x3f3f3f3f;
    const ll LNF  = 0x3f3f3f3f3f3f;
    inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
    inline ll  gcd(ll  a, ll  b) { return b ? gcd(b, a % b) : a; }
    inline int lcm(int a, int b) { return a * b / gcd(a, b); }
    
    const int N = 2e5 + 10;
    
    int n;
    ll x, sd[N * 2], v[N * 2], sv[N * 2];
    int d[N * 2];
    
    int main(){
        cin >> n >> x;
        for(int i = 1; i <= n; i ++){
            scanf("%d", &d[i]);
            d[i + n] = d[i]; // 由于是循环的,但 x < d1 + d2 + .. + dn 的,所以我们存两遍即可
        }
        sd[0] = 0; // 前缀和数组
        for(int i = 1; i <= n + n; i ++) {
            sd[i] = sd[i - 1] + d[i];
            v[i] = 1ll * d[i] * (d[i] + 1) / 2; // v[i] 是对于 i 这个月的总价值
            sv[i] = sv[i - 1] + v[i]; // 前缀和
        }
    
        ll ans = 0;
    
        for(int i = n + 1; i <= n + n; i ++){
            ll t = sd[i] - x; // 从第 i 个月最后一天往前走 x 天
            // 最后停止第 j 个月,也就是说从第 j 个月的某一天开始到 第 i 月的最后一天
            int j = lower_bound(sd + 1, sd + 2 * n + 1, t) - sd;
            ll s = sd[i] - sd[j]; // 算出 [j + 1, i] 共多少天
            t = x - s; // 在第 j 个月还有 t 天
            ll tmp = sv[i] - sv[j]; // 这里是 [j + 1, i] 的总价值
            tmp += 1ll * (d[j] + d[j] - t + 1) * t / 2; // 加上第 j 个月的 t 天
            ans = max(ans, tmp);  
        //    printf("i = %d j = %d t = %lld
    ", i, j, t);
        }
        
        cout << ans << endl;
        
    
        return 0;
    }
    
    


    (E. Are You Fired?)

    (Description:)
      给定长度为 (n) 的数组 (a),问是否存在一个 (k) 使得数组任意一个长度为 (k) 的子序列的和 (>0),特别的是:数组中区间为 ([frac{n+1}{2}+1, n]) 的数都为 (x)
    (Solution:)
      由于后面的数都是一样的,比较特殊,所以我们可以从这里突破。设 (sum[i]) 代表 ([1,i]) 的和

    1. (x > 0)
      1. (sum[n] leq 0)
        显然是无解的
      2. (sum[n] > 0)
        (k = n)
    2. (x leq 0)
      (m = n - frac{n+1}{2}),那么 (k > m),否则在 ([m+1,n]) 就存在一个长度为 (k) 的子序列的和 (leq 0)。那么我们遍历一遍,算出 (k) 的一个可行范围即可。首先假设 (k = n),对于 (i = 1) 来说,和就是 (sum[k]),大于 (0) 就不要管,如果 (leq 0),那么我们就需要 (-x),来使和变大,随之 (k --),直到 (sum[k] > 0),接下来一次类推。
      (Code:)
    /*
    @Author: nonameless
    @Date:   2020-05-28 15:50:31
    @Email:  2835391726@qq.com
    @Blog:   https://www.cnblogs.com/nonameless/
    */
    #include <bits/stdc++.h>
    #define x first
    #define y second
    #define all(x) x.begin(), x.end()
    #define sz(x) (int)x.size()
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> PII;
    typedef pair<ll, ll> PLL;
    const double PI  = acos(-1.0);
    const double eps = 1e-8;
    const int INF = 0x3f3f3f3f;
    const ll LNF  = 0x3f3f3f3f3f3f;
    inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
    inline ll  gcd(ll  a, ll  b) { return b ? gcd(b, a % b) : a; }
    inline int lcm(int a, int b) { return a * b / gcd(a, b); }
    
    const int N = 5e5 + 10;
    
    int n, x;
    int a[N];
    ll sum[N];
    
    int main(){
    
        cin >> n;
    
        int m = n + 1 >> 1;
    
        for(int i = 1; i <= m; i ++){
            scanf("%d", &a[i]);
            sum[i] = sum[i - 1] + a[i];
        }
    
        scanf("%d", &x);
        for(int i = m + 1; i <= n; i ++){
            a[i] = x;
            sum[i] = sum[i - 1] + x;
        }
    
        if(x > 0){
            if(sum[n] > 0) cout << n << endl;
            else puts("-1");
        } else{
            int k = n;
            m = n - m;
            for(int l = 1; l <= n; l ++){
                int r = l + k - 1; // 区间的右端点
                if(r > n) break; 
                ll tmp = sum[r] - sum[l - 1]; // [l, r] 的和
                while(tmp <= 0 && k > m) tmp -= x, k --;
                if(k <= m) break;
            }
            if(k <= m) puts("-1");
            else cout << k << endl;
        }
        
        return 0;
    }
    
    
  • 相关阅读:
    第七周
    跳ajax方式进行前后台交互之后台代码要怎么写
    写代码要注意细节,无谓的找前台bug
    mysql复习增删改查
    jquery获取value值
    sql查阅每一月的数据
    登录模块需要用到session留底
    前后台使用ajax传list的时候,用value[] 获取值
    Datables wrning(table id='example'):Cannot reinitialise DataTable.
    动态规划1
  • 原文地址:https://www.cnblogs.com/nonameless/p/12983889.html
Copyright © 2011-2022 走看看