zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 86 (Rated for Div. 2)

    传送门

    A. Road To Zero

    贪心。

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/4/26 22:36:10
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << std::endl; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
     
    int x, y, a, b;
     
    void run() {
        cin >> x >> y >> a >> b;
        if(x > y) swap(x, y);
        ll ans = 0;
        if(1ll * x * y < 0) {
            ans += 1ll * (-x) * a + 1ll * y * a;
        } else if(1ll * x * y == 0) {
            ans += 1ll * y * a;   
        } else {
            int d = abs(x - y);
            ans += 1ll * d * a;
            if (x < 0) x += d;
            else y -= d;
            x = abs(x);
            ll res = min(1ll * x * b, 2ll * x * a);
            ans += res;
        }
        cout << ans << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    B. Binary Period

    像构造(010101...)这样构造即可。

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/4/26 22:45:50
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << std::endl; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
     
    void run() {
        string s; cin >> s;
        int len = s.length();
        int cnt = 0;
        for (int i = 0; i < len; i++) {
            if (s[i] == '0') ++cnt;
        }
        if (cnt == 0 || cnt == len) {
            cout << s << '
    ';
            return;   
        }
        int cnt0 = cnt, cnt1 = len - cnt;
        string res = "";
        for (int i = 0; i < len; i++) {
            res += "01";
        }
        cout << res << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    C. Yet Another Counting Problem

    题意:
    给出(a,bleq 200),然后给出(q,qleq 500)个询问,每组询问给出区间([l,r],l,rleq 10^{18}),求出满足(lleq xleq r)(((x mod a) mod b) e ((x mod b) mod a))

    思路:
    显然询问我们可以拆分为两个前缀的询问。
    对于题目中给出的式子,现在(x)(acdot b)一个周期,我们用数组(sum)记录一个周期中的前缀信息:(sum_i)表示(0)~(i)中有多少个数不满足上述条件。
    对于一次询问(x),我们将([0,x])拆分为若干个([0,acdot b-1])这样的区间和剩下的区间,直接利用预处理信息计算即可。
    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/4/27 16:18:53
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << std::endl; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    
    int a, b, q;
    int sum[N];
    
    void run() {
        cin >> a >> b >> q;
        int n = a * b;
        for (int i = 0; i < n; i++) {
            if (i) sum[i] = sum[i - 1];
            if ((i % a) % b != (i % b) % a) ++sum[i];
        }
        auto calc = [&](ll r) {
            return r / n * sum[n - 1] + sum[r % n];
        };
        while (q--) {
            ll l, r; cin >> l >> r;
            ll ans = calc(r) - calc(l - 1);
            cout << ans << ' ';   
        }
        cout << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    Bonus: (a,b)限制改为(a,bleq 10^9)
    做法如下:
    我们考虑将式子变形(不妨(a<b)):

    [egin{aligned} ((xmod a)mod b)&=((xmod b)mod a)\ (xmod a)&=((xmod b)mod a)\ x-x\%b&equiv 0(mod a)\ bcdot lfloorfrac{x}{b} floor&equiv 0(mod a) end{aligned} ]

    此时(0leq xleq r),我们处理一个询问的答案。
    观察上面的式子,只有左边为(lcm(a,b))的倍数时才为合法答案,那么假设左边为(t)(lcm),就有(displaystyle bcdot lfloorfrac{x}{b} floor=tcdot frac{ab}{g}),化简为(displaystyle lfloorfrac{x}{b} floor=tcdot frac{a}{g}=tcdot a')
    显然(t)的个数容易求,即为(displaystyle frac{lfloorfrac{x}{b} floor}{a'}+1),当然对于每个(t)(x)(b)种取值情况。
    同时要注意一些边界情况,(x)不一定刚好取满(b)
    细节见代码:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/4/27 17:26:05
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << std::endl; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1e5 + 5;
    
    void run() {
        int a, b, q;
        cin >> a >> b >> q;
        if (a > b) swap(a, b);
        int g = __gcd(a, b);
        a /= g;
        auto calc = [&] (ll x) {
            ll now = x / b;
            ll res = (now / a + 1) * b;
            if (now % a == 0) {
                (res -= b) += x % b + 1;   
            }
            return res;
        };
        while (q--) {
            ll l, r; cin >> l >> r;
            ll ans = r - l + 1;
            ans -= calc(r) - calc(l - 1);
            cout << ans << ' ';
        }
        cout << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        int T; cin >> T; while(T--)
        run();
        return 0;
    }
    

    D. Multiple Testcases

    题意:
    给出(n)个数,每个数权值不超过(k),现在要从这些数中选出一些组成若干个序列,要求每个数恰好被选入一个序列之中。
    并且满足限制:(c_i)表示不小于(i)的数的个数,对于(1leq ileq k)都要满足。
    现在问最少构成多少个序列。
    保证(c_1geq c_2geq cdots geq c_k)

    思路:
    最简单的想法,我们从后往前贪心来选,每次找到一个合适的位置然后将其删除添加入序列中,反复执行这个过程即可。
    因为我们需要查找对应位置,并且要删除操作,所以用个(set)维护原序列剩下的数。
    时间复杂度(O(nlog^2n))
    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/4/26 23:46:45
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << std::endl; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e5 + 5;
    
    int n, k;
    int m[N], c[N];
    
    void run() {
        cin >> n >> k;
        multiset <int> s;
        for (int i = 1; i <= n; i++) {
            cin >> m[i];   
            s.insert(m[i]);
        }
        for (int i = 1; i <= k; i++) {
            cin >> c[i];   
        }
        vector <vector<int>> ans;
        while(sz(s)) {
            vector <int> res;
            while(1) {
                int l = 1, r = k + 1, mid;
                auto chk = [&] (int x) {
                    auto it = s.lower_bound(x);
                    if(it != s.end() && c[*it] >= sz(res) + 1) {
                        return true;
                    }
                    return false;
                };
                while(l < r) {
                    mid = (l + r) >> 1;
                    if(chk(mid)) l = mid + 1;
                    else r = mid;
                }   
                auto it = s.lower_bound(l - 1);
                if(it == s.end() || *it != l - 1) break;
                s.erase(it);
                res.push_back(l - 1);
            }
            ans.push_back(res);
        }
        cout << sz(ans) << '
    ';
        for (int i = 0; i < sz(ans); i++) {
            cout << sz(ans[i]);
            for (auto it : ans[i]) {
                cout << ' ' << it;
            }   
            cout << '
    ';
        }
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    

    这个题的时间复杂度还可以进一步优化。
    我们注意到假设最后的答案为(k),那么将原数组像(1,2,cdots,k,1,2cdots,k,1,cdots)这样进行分组肯定符合条件。
    所以我们二分答案,直接将原序列像上面进行分组然后check即可,时间复杂度为(O(nlogn))
    这个题还可以做到(O(n))。我们现在只需要快速求出最小的(k)即可。
    那么遍历一遍,对每个位置求出按照当前位置作为开头最小的分段数,这里面取最大值即是答案。
    假设(i)得到(x)(j,i<j)得到(y),若(yleq x),那么分为(x)组也可以满足条件;否则分(y)组才行,分(y)组也满足(i)位置的限制。
    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/4/27 16:10:31
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << std::endl; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e5 + 5;
    
    int n, k;
    int m[N], c[N], cnt[N], suf[N];
    
    void run() {
        cin >> n >> k;
        for (int i = 1; i <= n; i++) {
            cin >> m[i];
            ++cnt[m[i]];
        }
        sort(m + 1, m + n + 1);
        for (int i = k; i >= 1; i--) {
            suf[i] = suf[i + 1] + cnt[i];   
        }
        for (int i = 1; i <= k; i++) {
            cin >> c[i];   
        }
        int res = 0;
        for (int i = 1; i <= k; i++) {
            res = max(res, (suf[i] - 1) / c[i] + 1);   
        }
        cout << res << '
    ';
        vector <vector <int>> ans(res);
        for (int i = 1; i <= n; i++) {
            ans[(i - 1) % res].push_back(m[i]);
        }
        for (int i = 0; i < res; i++) {
            cout << sz(ans[i]);
            for (auto it : ans[i]) cout << ' ' << it;
            cout << '
    ';   
        }
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    

    感觉(O(nlogn))的做法是最自然的,“性价比”也比较高。

    E. Placing Rooks

    题意:
    给出一个(ncdot n)的棋盘,现在要在棋盘上放置(n)个棋子,每个棋盘能够攻击到在同一行、同一列的格子。
    现在问满足如下条件的棋子放置总情况个数:

    • 棋盘每个格子都能被攻击到;
    • 恰好有(k)对棋子能互相攻击,一对棋子能互相攻击的条件是这对棋子位于同一行或者同一列,并且中间没有其它棋子。

    比如下图为(n=3,k=2)的一种合法情况:

    思路:
    因为保证每个格子都处于攻击之下,所以每一行/每一列都必须有一个棋子,我们接下来考虑行的情况,列的情况同理。
    注意到有这样一个事实:

    • 在每一行放置一个棋子的情况下,互相攻击的棋子必须在同一列,并且将(n)个棋子放入(t)列中,每一列至少有一个,总的攻击的对数为(n-t)

    挺容易证明的,假设现在(t)列共有(k)对棋子互相攻击,那么有(x_1+x_2+cdots+x_t=k),令(y_i=x_i+1),那么(y_i)即是第(i)列的棋子个数,所以就有(y_1+y_2+cdots+y_t=n)。现在已知(y_1+y_2+cdots+y_t),那么很容易推出(x_1+x_2+cdots+x_t)

    那么此时我们所求的方案数为(displaystyle {nchoose n-k}cdot egin{Bmatrix} n \ n-k end{Bmatrix}cdot(n-k)!)
    后者为第二类斯特林数,因为我们这里不同的顺序会算上所有情况,那么最后还要乘以一个阶乘。
    第二类斯特林数可以直接通过容斥来求,可以参见我之前写的博客
    代码如下:

    Code
    /*
     * Author:  heyuhhh
     * Created Time:  2020/4/27 0:38:49
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #include <assert.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << std::endl; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
      template <template<typename...> class T, typename t, typename... A> 
      void err(const T <t> &arg, const A&... args) {
      for (auto &v : arg) std::cout << v << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 2e5 + 5, MOD = 998244353;
    
    int qpow(ll a, ll b) {
        ll res = 1;
        while(b) {
            if(b & 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return res;
    }
    ll n, k;
    int fac[N], inv[N];
    
    int C(int n, int m) {
        return 1ll * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
    }
    
    void run() {
        cin >> n >> k;
        if (k >= n) {
            cout << 0 << '
    ';
            return;
        }
        fac[0] = 1;
        for (int i = 1; i < N; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
        inv[N - 1] = qpow(fac[N - 1], MOD - 2);
        for (int i = N - 2; i >= 0; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
        int ans = 0;
        for (int i = 0; i <= n - k; i++) {
            int res = 1ll * C(n - k, i) * qpow(n - k - i, n) % MOD;
            if(i & 1) res = MOD - res;
            ans = (ans + res) % MOD;
        }
        ans = 1ll * ans * C(n, n - k) % MOD;
        if(k) (ans <<= 1) %= MOD;
        cout << ans << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        run();
        return 0;
    }
    
  • 相关阅读:
    DedeCMS图集上传图片报错,FILEID:X 错误处理办法
    AE10.0打开MxD或shp文件时提示“The specified path is invalid”
    未能加载AE的ESRI.ArcGIS.3Danalyst.dll等程序集
    Intel Parallel Studio 2011: error2350 FDI server error
    Android Google Map APIKey申请
    关于程序堆栈的解释
    Major and Minor Numbers (主次设备号)这个听说过
    linux字符设备驱动之LED
    linux下ioctl函数学习
    Some Important Data Structures
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/12789146.html
Copyright © 2011-2022 走看看