DISCO Presents Discovery Channel Code Contest 2020 Qual 题解

A

枚举一下

#include <bits/stdc++.h>
using namespace std;
int main() {
    int x, y;
    cin >> x >> y;
    int ans = 0;
    if(x == 1) {
        ans += 300000;
    }
    if(x == 2) {
        ans += 200000;
    }
    if(x == 3) {
        ans += 100000;
    }
    if(y == 1) {
        ans += 300000;
    }
    if(y == 2) {
        ans += 200000;
    }
    if(y == 3) {
        ans += 100000;
    }
    if(x == 1 && y == 1) {
        ans += 400000;
    }
    cout << ans << '\n';
    return 0;
}
View Code

B

枚举一下断点

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    vector<ll> a(n);
    ll sum = 0;
    for(int i = 0; i < n; ++i) {
        cin >> a[i];
        sum += a[i];
    }
    ll pre = 0, ans = sum;
    for(int i = 0; i < n; ++i) {
        pre += a[i];
        ans = min(ans, abs(2LL * pre - sum));
    }
    cout << ans << '\n';
    return 0;
}
View Code

C

有草莓的行分段涂 没有的和有的合并

#include <bits/stdc++.h>
using namespace std;
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    int cnt = 0;
    vector<vector<int> > a(n, vector<int>(m, 0));
    for(int i = 0; i < n; ++i) {
        string s;
        cin >> s;
        for(int j = 0; j < m; ++j) {
            if(s[j] == '#') {
                a[i][j] = ++cnt;
                for(int k = j - 1; ~k; --k) {
                    if(a[i][k] || s[k] == '#') {
                        break;
                    }
                    a[i][k] = cnt;
                }
                for(int k = j + 1; k < m; ++k) {
                    if(a[i][k] || s[k] == '#') {
                        break;
                    }
                    a[i][k] = cnt;
                }
            }
        }
    }
    cout << '\n';
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < m; ++j) {
            if(!a[i][j]) {
                continue;
            }
            for(int k = i - 1; ~k; --k) {
                if(a[k][j]) {
                    break;
                }
                a[k][j] = a[i][j];
            }
            for(int k = i + 1; k < n; ++k) {
                if(a[k][j]) {
                    break;
                }
                a[k][j] = a[i][j];
            }
        }
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < m; ++j) {
            cout << a[i][j] << ' ';
        }
        cout << '\n';
    }
    return 0;
}
View Code

D

思考一下发现 顺序与答案无关 (一个不严谨的证明:和是不变的 所以无关) 

如果不进位的话 答案就是$\sum_{i=1}^{n}{d_i}-1$

考虑进位 那么每进一次位就是多出来一个1 

设$sum=\sum_{i=1}^{n}{d_i*c_i}$

那么每次进位相当于$sum - 9$

如果$sum<10$停止

那么答案就是$\sum_{i=1}^{n}{d_i}-1 + \frac{\sum_{i=1}^{n}{d_i*c_i} - 1}{9}$

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 2e5 + 5;
int n;
ll d[maxn], c[maxn];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    for(int i = 1; i <= n; ++i) {
        cin >> d[i] >> c[i];
    }
    ll sum = 0, ans = 0;
    for(int i = 1; i <= n; ++i) {
        ans += c[i];
        sum += d[i] * c[i];
    }
    cout << ans - 1 + (sum - 1) / 9 << '\n';
    return 0;
}
View Code

E

这个题不错

如果能找出一个长度为$n$且红球蓝球数量差$<=1$的序列 并且知道其中一个红球和一个蓝球的位置 那么就能问出来所有了

由于红球有n个 蓝球有n个 这样的序列肯定是存在的 

设$ask(l, r)$表示询问$l-r$ 并且$r - l + 1 = n$

假设$ask(1,n)=R$ 那么 $ask(n + 1, 2n) = B$

并且存在某一个$i$使得$ask(i,i+n-1)$和$ask(i+1,i+n)$不同

接着可以发现 这样的i是可以二分得出的

那么先二分出这样的分界点 然后将其他所有点带进这个序列询问即可

花费的询问次数是$2n-2 + log(n)+1 < 210$

#include <bits/stdc++.h>
using namespace std;
const int maxn = 205;
int n, L, R;
int ans[maxn];
int Ask(int l, int r) {
    cout << '?';
    for(int i = l; i <= r; ++i) {
        cout << ' ' << i;
    }
    cout << '\n';
    string ret;
    cin >> ret;
    return ret == "Red" ? -1 : 1; 
}
int Ask(int x) {
    cout << '?' << ' ' << x;
    for(int i = 1; i <= 2 * n; ++i) {
        if(i != L && i != R && (L < i && i < R) != (L < x && x < R)) {
            cout << ' ' << i;
        }
    }
    cout << '\n';
    string ret;
    cin >> ret;
    return ret == "Red" ? -1 : 1;
}
int main() {
    cin >> n;
    int prv = Ask(1, n);
    int l = 1, r = n + 1;
    while(r - l > 1) {
        int mid = l + r >> 1;
        if(Ask(mid, mid + n - 1) == prv) {
            l = mid;
        } else {
            r = mid;
        }
    }
    ans[l] = prv;
    ans[l + n] = -prv;
    L = l;
    R = l + n;
    for(int i = 1; i <= 2 * n; ++i) {
        if(i != L && i != R) {
            ans[i] = Ask(i);
        }
    }
    cout << "! ";
    for(int i = 1; i <= 2 * n; ++i) {
        cout << (ans[i] == -1 ? 'R' : 'B');
    }
    cout << '\n';
    return 0;
}
View Code

F

好难啊

先将方阵分解成小方阵 小方阵中$d=1$ 也就是每次只走一步 不同方阵之间互相独立

小方阵的长宽分别是$n/gcd(n,d)$和$m/gcd(m,d)$

然后考虑方案 

只有向下和不动方案是是$2^{m/gcd(m,d)}-1$

只有向左和不动的方案是$2^{n/gcd(n,d)}-1$

同时向下和向左的方案是$2^{gcd(n/gcd(n,d), m/gcd(m,d))}-1$

最后一个比较抽象 这么考虑 把方阵按对角线分组 这样就有$gcd(n/gcd(n,d), m/gcd(m,d))$组

每一组必须行动一致 向左或向下 这样为什么是对的 因为对于每个格子单独考虑 每一秒都只有一个人进一个人出 不会撞上

如果对角线行动不一致 那么就会撞上

最后乘上矩形数即可

这种问题就是置换群的套路 分解成循环节 问题变得简单后再分类讨论

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int P = 1e9 + 7;
ll h, w, t;
ll power(ll x, ll t) {
    ll ret = 1;
    for(; t; t >>= 1, x = x * x % P) {
        if(t & 1) {
            ret = ret * x % P;
        }
    }
    return ret;
}
int main() {
    cin >> h >> w >> t;
    ll n = h / __gcd(h, t), m = w / __gcd(w, t);
    ll tmp = (power(2LL, n) + power(2LL, m) + power(2LL, __gcd(n, m)) - 3 + P) % P;
    ll c = __gcd(h, t) * __gcd(w, t);
    cout << power(tmp, c) << '\n';
    return 0;
}
View Code

 

posted @ 2020-02-04 10:24  19992147  阅读(272)  评论(0编辑  收藏  举报