Educational Codeforces Round 88 (Rated for Div. 2) A - E 解题报告

题目链接


\(A. Berland Poker\)

\(Description:\)
  给定 \(n\) 张牌,其中有 \(m\) 张特殊的牌,把所有牌平均分给 \(k\) 个人,问你手中的特殊牌的数量 \(-(k - 1)\) 个人中拥有最多特殊牌的数量的最大值是多少?
\(Solution:\)
  先把特殊牌分给你,其他人在平均分即可。
\(Code:\)

/*
@Author: nonameless
@Date:   2020-05-29 09:20:42
@Email:  2835391726@qq.com
@Blog:   https://www.cnblogs.com/nonameless/
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
const double eps = 1e-8;
const double PI  = acos(-1.0);
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, k;
        cin >> n >> m >> k;
        int cnt = n / k;
        if(cnt >= m) cout << m << endl;
        else{
            cnt -= (m - cnt) / (k - 1) + ((m - cnt) % (k - 1) != 0);
            cout << cnt << endl;
        }
    }
    return 0;
}


\(B. New Theatre Square\)

\(Description:\)
  给定 \(n \times m\) 的矩阵,让你来用 \(1 \times 2\)\(1 \times 1\) 的砖来填充矩阵中的 \(.\),砖只能横着放,问最小代价是多少?
\(Solution:\)
  遍历每一行,算出连续的 \(.\) 的个数即可。
\(Code:\)

/*
@Author: nonameless
@Date:   2020-05-29 09:25:29
@Email:  2835391726@qq.com
@Blog:   https://www.cnblogs.com/nonameless/
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
const double eps = 1e-8;
const double PI  = acos(-1.0);
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 = 1e2 + 10, M = 1e3 + 10;

int n, m, x, y;
char s[N][M];

int main(){

    int t; cin >> t;
    while(t --){
        cin >> n >> m >> x >> y;
        for(int i = 1; i <= n; i ++)
            scanf("%s", s[i] + 1);
        y = min(x + x, y);

        int ans = 0;
        for(int i = 1; i <= n; i ++){

            int cnt = 0;
            for(int j = 1; j <= m; j ++){
                if(s[i][j] == '.') cnt ++;
                else{
                    ans += cnt / 2 * y + (cnt % 2) * x;
                    cnt = 0;
                }
            }
            ans += cnt / 2 * y + (cnt % 2) * x;
        }
        cout << ans << endl;
    }
    
    return 0;
}


\(C. Mixing Water\)

\(Description:\)
  一杯热水的温度是 \(h\),一杯冷水的温度是 \(c\),按照热冷热冷热的顺序往桶里倒水,使其平均温度 \(tb\) 最接近 \(t\),问最少加几杯水?
\(Solution:\)
  首先要知道的是如果我们加了偶数杯,也就是说热水和冷水各加了 \(x\) 杯,那么可以得到:\(\frac{x(h+c)}{2x} = \frac{h+c}{2}\),所以对于偶数杯的情况,就考虑完了。对于奇数杯,也就是在热冷各加了 \(x\) 杯后,再加了 \(1\) 杯热水,也就是说(设 \(a = h + c\)):

\[tb = \frac{ax+h}{2x+1} = \frac{\frac{a}{2}(2x+1)+h-\frac{a}{2}}{2x+1}=\frac{a}{2}+\frac{h-\frac{a}{2}}{2x+1} \]

  由于 \(h > \frac{a}{2}\),所以 \(tb\) 是关于 \(x\) 的递减函数,那么我们就可以二分解决了。
\(Code:\)

/*
@Author: nonameless
@Date:   2020-05-29 09:38:19
@Email:  2835391726@qq.com
@Blog:   https://www.cnblogs.com/nonameless/
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
const double eps = 1e-8;
const double PI  = acos(-1.0);
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 h, c, t;

double calc(int cnt){ // 对于杯数下的平均温度
    int a = cnt / 2, b = cnt % 2;
    double res = (1ll * a * (h + c) + b * h) * 1.0 / cnt;
    return res; 
}

int main(){

    int test; cin >> test;
    while(test --){
        cin >> h >> c >> t;

        // first 是温度差,second 是杯数,优先按温度差排序
        vector<pair<double, int> > vec; 

        vec.pb({fabs((h + c) / 2.0 - t), 2}); 
        
        int l = 0, r = 1e9;
        int more = 1, less = 1; // 一个大于 t, 一个小于等于 t
        while(l <= r){
            int mid = l + r >> 1;
            int x = 2 * mid + 1; // 这样 x 就一定是奇数了
            double tb = calc(x); 
            if(tb > t){
                more = x;
                l = mid + 1;
            } else{
                less = x;
                r = mid - 1;
            }
        }

        vec.pb({fabs(t - calc(less)), less});
        vec.pb({fabs(t - calc(more)), more});

        sort(all(vec)); // 排序
        cout << vec[0].y << endl;


    }
    return 0;
}


\(D. Yet Another Yet Another Task\)

\(Description:\)
  求某一段区间和减去区间的最大值后的所得得值最大可以是多少?特别得是 \(-30 \leq a_i \leq 30\)
\(Solution:\)
  题目已经明示了我们可以选择区间的最大值得只有 \([1, 30]\)(如果区间的最大值为负,那么我们为了结果最大,我们只有选长度为 \(1\) 的区间),所以我们就可以去枚举我们选出的区间的最大值,然后遍历整个数组,只要区间在此处不中断就与结果取 \(max\)
\(Code:\)

/*
@Author: nonameless
@Date:   2020-05-29 14:32:55
@Email:  2835391726@qq.com
@Blog:   https://www.cnblogs.com/nonameless/
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
const double eps = 1e-8;
const double PI  = acos(-1.0);
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 = 1e5 + 10;

int n, a[N];

int main(){
    
    cin >> n;
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);

    int ans = 0;
    for(int i = 1; i <= 30; i ++){
        int tmp = 0; // 连续的和
        for(int j = 1; j <= n; j ++){
            // 遇到比我们选择的区间最大值还大,就说明他一定不在我们所选的区间中,那么到这里区间就中断了,所以 tmp = 0;
            if(a[j] > i) tmp = 0; 
            else{
                tmp = max(0, tmp + a[j]); // 如果到这里区间和为负,那么我们应该舍弃掉
                ans = max(ans, tmp - i);
            }
        }
    }

    cout << ans << endl;
    
    return 0;
}


\(E. Modular Stability\)

\(Description:\)
  给定 \(n,k\),让你构造一个长度为 \(k\) 的数组 \(a\),然后将 \(a\) 数组全排列得到 \(k!\)\(p\) 数组,要求对于任意的 \(p\) 数组和任意一个 \(x > 0\) 满足:

\[(((x \mod a_1) \mod a_2) ... \mod a_k) = (((x \mod p_1) \mod p_2) ... \mod p_k) \]

  特别的:\(1\leq a_1 < a_2 < ... < a_k\)。求 \(a\) 数组的个数?
\(Solution:\)
  要让其任意顺序的模数都相等,那么他们肯定是要满足某种规律的。我就猜测数组 \(a\) 一定是满足了第一项是后面所有项的因子,这个也很好证明:
  设数组 \(a\)\(d,\ t_1d,\ t_2d,\ t_{k-1}d\)。那么 \(x\) 也可以和 \(d\) 挂上钩,即 \(x = kd + c\),对于去模 \(a\) 数组的结果显然是 \(c\),对于去模 \(p\) 数组,遇到比 \(x\) 大的不会变,比 \(x\) 小的,那么 \(x\) 就会逐渐变小,但是 \(c\) 是始终存在的,直到遇到 \(d\),变为 \(c\),而之后的数都比 \(c\) 大,显然 \(c\) 就是结果,与模 \(a\) 数组的结果一致,所以是可行的。
  那么我们就可以去枚举 \(d\),然后算出 \([1,\ n]\)\(d\) 的倍数的个数,排列组合即可求解。
\(Code:\)

/*
@Author: nonameless
@Date:   2020-05-29 11:25:26
@Email:  2835391726@qq.com
@Blog:   https://www.cnblogs.com/nonameless/
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
const double eps = 1e-8;
const double PI  = acos(-1.0);
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 mod = 998244353;
const int N = 5e5 + 10;

ll f[N];

ll fPow(ll a, ll b){
    ll res = 1;
    while(b){
        if(b & 1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res;
}

ll C(int a, int b){
    return f[a] * fPow(f[b] * f[a - b] % mod, mod - 2);
}

int main(){

    int n, k;
    cin >> n >> k;

    f[0] = 1;
    for(int i = 1; i <= n; i ++) f[i] = f[i - 1] * i % mod;

    ll ans = 0;
    for(int i = 1; i <= n; i ++){
        int d = n / i - 1;
        if(d < k - 1) break;
        ans = (ans + C(d, k - 1)) % mod;
    }

    cout << ans << endl;


    return 0;
}

posted @ 2020-05-29 16:55  nonameless  阅读(177)  评论(0编辑  收藏  举报