zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 80 (Rated for Div. 2) ABCDE 题解

    Educational Codeforces Round 80 (Rated for Div. 2)

    A. Deadline

    如果n>=d 直接yes

    否则对于公式

    (x+ceil(d/(x+1))<=n)

    两边同时乘以x+1

    会得到一个关于x的一元二次方程,

    通过求根公式解出较小的那一个根x1,

    然后在(x1+-3) 的范围内找到(x+ceil(d/(x+1))) 的最小值与n比较即可。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <vector>
    #include <iomanip>
    #define ALL(x) (x).begin(), (x).end()
    #define sz(a) int(a.size())
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define pii pair<int,int>
    #define pll pair<long long ,long long>
    #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    #define MS0(X) memset((X), 0, sizeof((X)))
    #define MSC0(X) memset((X), '', sizeof((X)))
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define eps 1e-6
    #define gg(x) getInt(&x)
    #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
    #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
    #define du2(a,b) scanf("%d %d",&(a),&(b))
    #define du1(a) scanf("%d",&(a));
    using namespace std;
    typedef long long ll;
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
    ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
    void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
    ");}}}
    void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
    ");}}}
    
    inline void getInt(int* p);
    const int maxn = 1000010;
    const int inf = 0x3f3f3f3f;
    /*** TEMPLATE CODE * * STARTS HERE ***/
    int t;
    ll n, d;
    ll check(ll x)
    {
        return x + ceil(1.0 * d / (x + 1));
    }
    typedef long double ld;
    int main()
    {
        //freopen("D:\code\text\input.txt","r",stdin);
        //freopen("D:\code\text\output.txt","w",stdout);
        // gbtb;
        cin >> t;
        while (t--)
        {
    
            cin >> n >> d;
            if (d <= n)
            {
                cout << "YES" << endl;
            } else
            {
                int isok = 0;
                ld b = 1 - n;
                ld c = d - n;
                ld xw = (-b - sqrtl(b * b - 4.0 * c)) * 0.5;
                ll xx = ll(xw);
                ll w = inf;
                repd(i, max(0ll, xx - 3), min(n * 1ll, xx + 3))
                {
                    w = min(w, check(i));
                }
                if (w <= n)
                {
                    isok = 1;
                }
                if (isok)
                {
                    cout << "YES" << endl;
                } else
                {
                    cout << "NO" << endl;
                }
            }
        }
    
        return 0;
    }
    
    inline void getInt(int* p) {
        char ch;
        do {
            ch = getchar();
        } while (ch == ' ' || ch == '
    ');
        if (ch == '-') {
            *p = -(getchar() - '0');
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 - ch + '0';
            }
        }
        else {
            *p = ch - '0';
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 + ch - '0';
            }
        }
    }
    

    B. Yet Another Meme Problem

    通过打表可以发现

    满足 (a cdot b + a + b = conc(a, b)) 的b 为9 ,99,999,9999...等等

    所以答案即为 A*F(B)

    F(B) 为 <=B 的 9 ,99,999,9999...等等的个数

    F(B) 的求法非常简单。

    int t;
    ll a, b;
    ll F(ll x)
    {
        ll res = 0ll;
        ll base = 9ll;
        while (base <= x)
        {
            base *= 10;
            base += 9;
            res++;
        }
        return res;
    }
    int main()
    {
        //freopen("D:\code\text\input.txt","r",stdin);
        //freopen("D:\code\text\output.txt","w",stdout);
        gbtb;
        cin >> t;
        while (t--)
        {
            cin >> a >> b;
            a *= F(b);
            cout << a << endl;
        }
        return 0;
    }
    

    C. Two Arrays

    (dp1[i][j]) 为长度为i,以j为结尾的单调不下降序列方案数

    (dp2[i][j]) 为长度为i,以j为结尾的单调不上升序列方案数

    当j1>=j2 时 以j1为结尾的单调不下降序列和以j2为结尾的单调不上升序列

    自动满足:

    • ai≤bi for any index ii from 11 to mm;
    • array a is sorted in non-descending order;
    • array b is sorted in non-ascending order.

    然后扫一遍计算答案即可,可以用前缀和来优化,但是这个数据范围没啥必要。

    ll dp1[11][1111];
    ll dp2[11][1111];
     
    ll n;
    ll m;
    const ll mod = 1e9 + 7;
    int main()
    {
        //freopen("D:\code\text\input.txt","r",stdin);
        //freopen("D:\code\text\output.txt","w",stdout);
        cin >> n >> m;
        repd(i, 1, n)
        {
            dp1[1][i] = 1;
            dp2[1][i] = 1;
        }
        repd(i, 2, m)
        {
            repd(j, 1, n)
            {
                repd(k, 1, j)
                {
                    dp1[i][j] += dp1[i - 1][k];
                    dp1[i][j] %= mod;
                }
                repd(k, j, n)
                {
                    dp2[i][j] += dp2[i - 1][k];
                    dp2[i][j] %= mod;
                }
            }
        }
    
        ll ans = 0ll;
        repd(i, 1, n)
        {
            repd(j, 1, i)
            {
                ans += dp2[m][i] * dp1[m][j] % mod;
                ans %= mod;
            }
        }
        cout << ans << endl;
        return 0;
    }
    

    D. Minimax Problem

    极小极大问题 普遍容易通过转化为二分极小值,然后验证可行性的问题。

    本题也不例外,我们二分(min limits_{k = 1}^{m} b_k) 的数值mid。

    然后去check 是否存在两个数组满足此条件。

    check的方法如下:

    我们遍历这n个数组,对于第i个数组的第j个数a(i,j) 是否大于等于mid用一个int整数进行二进制的状态压缩表示,然后将int数值加入一个unordered_set 中。

    然后对unset中的元素进行两两测试是否按位与起来满足 m个数均为1.

    为什么要用unset呢?

    紧扣题目的数据范围,m<=8, 那么对于每一次check一共也就只有 2^8 个情况,

    两两测试的时候最大也就是2^16次,依次来降低时间复杂度。

    二分的时间复杂度时O(1e9)

    check的时间复杂度为O(n*m+2^16)

    总时间复杂度为:(O(log_2(1e9)*(n*m+2^{16})))

    #include <bits/stdc++.h>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <vector>
    #include <iomanip>
    #define ALL(x) (x).begin(), (x).end()
    #define sz(a) int(a.size())
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define pii pair<int,int>
    #define pll pair<long long ,long long>
    #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    #define MS0(X) memset((X), 0, sizeof((X)))
    #define MSC0(X) memset((X), '', sizeof((X)))
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define eps 1e-6
    #define gg(x) getInt(&x)
    #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
    #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
    #define du2(a,b) scanf("%d %d",&(a),&(b))
    #define du1(a) scanf("%d",&(a));
    using namespace std;
    typedef long long ll;
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
    ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
    void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
    ");}}}
    void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
    ");}}}
    
    inline void getInt(int* p);
    const int maxn = 1000010;
    const int inf = 0x3f3f3f3f;
    /*** TEMPLATE CODE * * STARTS HERE ***/
    int n, m;
    int a[300010][9];
    unordered_set<int> st;
    int t1, t2;
    bool check(int x)
    {
        st.clear();
        int t;
        repd(i, 1, n)
        {
            t = 0;
            repd(j, 1, m)
            {
                if (a[i][j] >= x)
                {
                    t |= (1 << (j - 1));
                }
            }
            st.insert(t);
        }
        for (auto y : st)
        {
            for (auto z : st)
            {
                if ((y | z) == (1 << m) - 1)
                {
                    t1 = y;
                    t2 = z;
                    return 1;
                }
            }
        }
    }
    int main()
    {
        //freopen("D:\code\text\input.txt","r",stdin);
        //freopen("D:\code\text\output.txt","w",stdout);
        du2(n, m);
        repd(i, 1, n)
        {
            repd(j, 1, m)
            {
                du1(a[i][j]);
            }
        }
        int l = 0;
        int r = 1e9;
        int mid;
        int ans;
        while (l <= r)
        {
            mid = (l + r) >> 1;
            if (check(mid))
            {
                l = mid + 1;
                ans = mid;
            } else
            {
                r = mid - 1;
            }
        }
        int ans1, ans2;
        repd(i, 1, n)
        {
            int t = 0;
            repd(j, 1, m)
            {
                if (a[i][j] >= ans)
                {
                    t |= (1 << (j - 1));
                }
            }
            if (t == t1)
            {
                ans1 = i;
    
            }
            if (t == t2)
            {
                ans2 = i;
            }
        }
        printf("%d %d
    ", ans1, ans2 );
    
        return 0;
    }
    
    inline void getInt(int* p) {
        char ch;
        do {
            ch = getchar();
        } while (ch == ' ' || ch == '
    ');
        if (ch == '-') {
            *p = -(getchar() - '0');
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 - ch + '0';
            }
        }
        else {
            *p = ch - '0';
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 + ch - '0';
            }
        }
    }
    
    
     
    

    E. Messenger Simulator

    对于n个数的数组,我们先初始为 n,n-1,n-2,,,,3 ,2,1 的情况 (即n~1的降序排列)

    然后把给定的m个数依次放在数组的尾部。

    例如样例1 为:

    5 4 3 2 1 3 5 1 4

    定义数组vis[i] 代表数字i上一次出现在哪个位置,初始为0。

    我们维护两个数组 be[i] 代表数字i出现的最前的位置,ed[i] 代表数字i 出现 的最后的位置。

    如果有把数字i提前到第一位,be[i]=1,否则be[i]=i

    ed[i] 为上述数组中紧挨着的两个i之间的数字种类数,或者最后一个数字i到结束有多少种类的数字。

    因为如果出现第2次以及以上次数i时,证明将数字i提到数组的最前端了,那么i之前的位置一定是一个偏后面的位置,我们维护ed[i]的最大值即可。

    至于“ed[i]的另一个情况,最后一个数字i到结束有多少种类的数字”,可以通过样例自行理解一下。

    因为询问的区间均为有序的区间,所以可以直接用树状数组进行维护即可。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <vector>
    #include <iomanip>
    #define ALL(x) (x).begin(), (x).end()
    #define sz(a) int(a.size())
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define pii pair<int,int>
    #define pll pair<long long ,long long>
    #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    #define MS0(X) memset((X), 0, sizeof((X)))
    #define MSC0(X) memset((X), '', sizeof((X)))
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define eps 1e-6
    #define gg(x) getInt(&x)
    #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
    #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
    #define du2(a,b) scanf("%d %d",&(a),&(b))
    #define du1(a) scanf("%d",&(a));
    using namespace std;
    typedef long long ll;
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
    ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
    void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
    ");}}}
    void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
    ");}}}
    
    inline void getInt(int* p);
    const int maxn = 1000010;
    const int inf = 0x3f3f3f3f;
    /*** TEMPLATE CODE * * STARTS HERE ***/
    int n, m;
    int a[maxn];
    int tree[maxn];
    int lowbit(int x)
    {
        return x & (-x);
    }
    void add(int pos, int val)
    {
        while (pos < maxn)
        {
            tree[pos] += val;
            pos += lowbit(pos);
        }
    }
    int ask(int pos)
    {
        int res = 0;
        while (pos>0)
        {
            res += tree[pos];
            pos -= lowbit(pos);
        }
        return res;
    }
    
    int be[maxn];
    int ed[maxn];
    int vis[maxn];
    int main()
    {
        //freopen("D:\code\text\input.txt","r",stdin);
        //freopen("D:\code\text\output.txt","w",stdout);
        du2(n, m);
        repd(i, 1, n)
        {
            a[i] = n - i + 1;
        }
        repd(i, n + 1, n + m)
        {
            du1(a[i]);
            be[a[i]] = 1;
        }
        repd(i, 1, n)
        {
            if (!be[i])
            {
                be[i] = i;
            }
        }
        repd(i, 1, n + m)
        {
            if (!vis[a[i]])
            {
                add(i, 1);
            } else
            {
                add(vis[a[i]], -1);
                add(i, 1);
            }
    //        chu(i);
            if (vis[a[i]])ed[a[i]] = max(ed[a[i]], ask(i) - ask(vis[a[i]] - 1));
            vis[a[i]] = i;
        }
        repd(i, 1, n)
        {
            ed[i] = max(ed[i], ask(n + m) - ask(vis[i] - 1));
        }
        repd(i, 1, n)
        {
            printf("%d %d
    ", be[i], ed[i] );
        }
    
        return 0;
    }
    
    inline void getInt(int* p) {
        char ch;
        do {
            ch = getchar();
        } while (ch == ' ' || ch == '
    ');
        if (ch == '-') {
            *p = -(getchar() - '0');
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 - ch + '0';
            }
        }
        else {
            *p = ch - '0';
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 + ch - '0';
            }
        }
    }
    
    
     
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    C语言博客作业01分支、顺序结构
    vue学习日记04
    vue学习日记01
    vue学习日记05
    vue学习日记02
    企业微信小程序注册遇到的一些事
    vue学习日记03
    Unix/Linux系统编程第十三章学习笔记
    OpenEuler 中C与汇编的混合编程(选做)
    《Unix/Linux系统编程》第五章学习笔记
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/12199373.html
Copyright © 2011-2022 走看看