Educational Codeforces Round 82 (Rated for Div. 2)

传送门

A. Erasing Zeroes

签到。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/2/12 22:35:56
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#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 << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 100 + 5;
 
int n;
char s[N];
int pre[N];
 
void run(){
    cin >> (s + 1);
    n = strlen(s + 1);
    for(int i = 1; i <= n; i++) pre[i] = pre[i - 1] + (s[i] == '0');
    int first = -1, end = -1;
    for(int i = 1; i <= n; i++) if(s[i] == '1') {
        if(first == -1) first = i;
        end = i;   
    }
    if(first == -1) {
        cout << 0 << '\n';
        return;   
    }
    cout << pre[end] - pre[first - 1] << '\n';
}
 
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. National Project

贪心即可。
因为至少要保证一半以上为高质量的公路,所以先计算出至少需要多少天。
然后在此基础上分情况考虑就行。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/2/12 22:41:34
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#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 << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
int n, g, b;
 
void run(){
    cin >> n >> g >> b;
    int need = (n + 1) / 2;
    int t = (need + g - 1) / g;
    ll tot = 1ll * (t - 1) * (g + b);
    ll r = need - 1ll * g * (t - 1);
    if(tot + r >= (ll)n) {
        cout << tot + r << '\n';
    } else cout << n << '\n';
}
 
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. Perfect Keyboard

题意:
给出\(s\)串,\(|s|\leq 200\)
现在构造一个由\(26\)个小写字母组成的\(t\)串,要求对于任意两个在\(s\)串中相邻的字符,在\(t\)串中都相邻。
如果不能构造则输出NO。

思路:
我们将相邻关系转化为图上面的连边关系,那么如果存在合法的答案,最终的图一定是由若干条链构成(单个点也视为一条链),即不存在一条环。
那么用邻接矩阵表示出图上面的关系然后直接\(dfs\)即可。
实现的时候有点细节,比如要通过删边避免重复走误判环,还要从度数为\(1\)的点开始搜等等。
代码如下:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/2/12 22:54:42
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#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 << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 200 + 5;
 
int n, tot;
char s[N], ans[26];
bool mp[26][26], chk[26];
 
bool dfs(int u) {
    chk[u] = true;
    ans[++tot] = 'a' + u;
    for(int i = 0; i < 26; i++) if(mp[u][i]) {
        if(chk[i]) return false;
        mp[u][i] = mp[i][u] = 0;
        if(!dfs(i)) return false;   
        mp[u][i] = mp[i][i] = 1;
    }
    return true;
}
 
void run(){
    memset(chk, 0, sizeof(chk));
    memset(mp, 0, sizeof(mp));
    tot = 0;
    cin >> (s + 1);
    n = strlen(s + 1);
    for(int i = 2; i <= n; i++) {
        mp[s[i] - 'a'][s[i - 1] - 'a'] = mp[s[i - 1] - 'a'][s[i] - 'a'] = 1;
    }
    for(int i = 0; i < 26; i++) {
        int t = 0;
        for(int j = 0; j < 26; j++) {
            if(mp[i][j]) ++t;
        }   
        if(t == 1) {
            if(!chk[i] && !dfs(i)) {
                cout << "NO" << '\n';
                return;
            }   
        }
        if(t > 2) {
            cout << "NO" << '\n';
            return;   
        }
    }
    for(int i = 0; i < 26; i++) {
        if(!chk[i] && !dfs(i)) {
            cout << "NO" << '\n';
            return;
        }
    }
    cout << "YES" << '\n';
    for(int i = 1; i <= tot; i++) cout << ans[i];
    cout << '\n';
}
 
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. Fill The Bag

题意:
现有一背包,容量为\(n,n\leq 10^{18}\),有\(m\)个物品,每个物品占用容量为\(a_i,1\leq a_i\leq 10^9\),保证对于每个\(a_i\),都存在一个非负整数\(x\),使得\(2^x=a_i\)
现在可以执行任意次如下操作:将\(a_i\)划分为两个\(\frac{a_i}{2}\)
现在要用最少的划分次数,来填满这个背包。

思路:
显然可以发现,如果对\(n\)进行二进制分解,那么我们只需要保证对应二进制位上面为\(1\)即可。
所以贪心策略为:对于某一位而言,肯定能用前面的来堆就用前面的,否则就把后面最近的一个分解,使得这一位为\(1\)
实现时我们从低位到高位考虑,某一位考虑完过后,这一位剩下的显然堆在后面最优。如果从高位往低位考虑,则贪心起来十分困难。
代码如下:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/2/12 23:21:06
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#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 << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
int a[N];
int cnt[64];
 
void run(){ 
    for(int i = 0; i < 64; i++) cnt[i] = 0;
    ll n; int m;
    cin >> n >> m;
    ll sum = 0;
    for(int i = 1; i <= m; i++) {
        cin >> a[i]; sum += a[i];
        int x = a[i] / 2, t = 0;
        while(x) t++, x /= 2; 
        ++cnt[t];
    }
    if(sum < n) {
        cout << -1 << '\n';
        return;   
    }
    int ans = 0;
    for(int i = 0; i < 64; i++) {
        bool need = false;
        if(n >> i & 1) need = true;
        if(cnt[i] == 0 && need) {
            for(int j = i + 1; j < 64; j++) {
                if(cnt[j] >= 1) {
                    ans += j - i;
                    for(int k = i; k < j; k++) ++cnt[k];
                    ++cnt[i], --cnt[j];
                    break;
                } 
            }
        }
        if(need) --cnt[i];
        cnt[i + 1] += cnt[i] / 2;
    }
    cout << ans << '\n';
}
 
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;
}

E. Erase Subsequences

题意:
给出一个字符串,现在可以执行如下操作不超过两次:

  • 选择任意一个\(s\)串的子序列,然后将其从\(s\)中移除,拼接在\(t\)串后面(初始\(t\)串为空)。

现在给出\(s\)串和\(t\)串,回答是否能从\(s\)串得到\(t\)串。

思路:
可以考虑枚举\(t\)串分隔位置,那么现在就相当于要从\(s\)串中选出两个不相交的子序列分别为\(t_1,t_2\)
最直接的实现是一个\(O(n^3)\)\(dp:dp_{i,j,k}\)表示现在位于\(s\)串的第\(i\)位,位于\(t_1\)的第\(j\)位,\(t_2\)的第\(k\)位,转移的时候直接枚举合法状态进行转移。总的时间复杂度为\(O(n^4)\)
现在我们对这个\(dp\)进行优化。
注意到我们其实并不需要关注\(s\)串匹配在了哪个位置,只要当\(t_1,t_2\)匹配完时,\(s\)串的指针不超过末尾字符即可。
那么定义\(dp_{i,j}:t_1\)匹配到了\(i,t_2\)匹配到了\(j\),此时需要\(s\)的最短长度为多少。那么转移的时候直接\(O(n^2)\)枚举即可。
所以总的时间复杂度为\(O(n^3)\)

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/2/13 9:56:57
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#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 << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 400 + 5;
 
int n, m;
char s[N], t[N];
int nxt[N][26];
int dp[N][N];
 
int solve(char *s, int n, char *t, int m) {
    memset(dp, INF, sizeof(dp));
    dp[0][0] = 0;
    for(int i = 0; i <= n; i++) {
        for(int j = 0; j <= m; j++) {
            if(i) dp[i][j] = min(dp[i][j], nxt[dp[i - 1][j]][s[i] - 'a']);
            if(j) dp[i][j] = min(dp[i][j], nxt[dp[i][j - 1]][t[j] - 'a']);
        }
    }
    return dp[n][m];
}
 
void run(){
    cin >> (s + 1) >> (t + 1);
    n = strlen(s + 1);
    m = strlen(t + 1);
    memset(nxt, 0, sizeof(nxt));
    for(int i = 0; i < 26; i++) nxt[n + 1][i] = n + 1;
    for(int i = n; i >= 0; i--) {
        for(int j = 0; j < 26; j++) {
            if(s[i + 1] == 'a' + j) nxt[i][j] = i + 1;
            else nxt[i][j] = nxt[i + 1][j];
        }
    }
    int ans = INF;
    for(int i = 1; i <= m; i++) {
        ans = min(ans, solve(t, i, t + i, m - i));
    }
    if(ans <= n) cout << "YES" << '\n';
    else cout << "NO" << '\n';
}
 
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;
}
posted @ 2020-02-13 15:30  heyuhhh  阅读(238)  评论(0编辑  收藏  举报