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

    传送门

    A. Prime Subtraction

    判断一下是否相差为(1)即可。

    B. Kill 'Em All

    随便搞搞。

    C. Standard Free2play

    题意:
    现在有一个高度为(h)的悬崖,每一层有平台,但可能是隐藏状态。
    高度为(h)的那层平台一定是在外面的,假设当前高度为(x),那么每次可以改变(x)(x-1)层平台的状态。
    规定一个人若从(x)掉到(x-1)或者(x-2)都没事,否则就出事了。
    问最少改变多少平台的状态,能够使在(h)高度的人顺利到达地面(高度为(0))。

    思路:
    我大概模拟了一下这个过程,然后发现对于连续的(x,x-1,cdots,x-k),最终答案是否加一与(x)(x-k)的奇偶性相关。
    并且从(h_i)(h_{i+1}),假设中间有空平台,其实最后到达的是(h_{i+1}-1),然后就这样模拟一下这个过程就行了。
    注意一下细节:最后到地面的时候记得判断一下高度是否大于(2),否则答案会加一。

    代码如下:

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    // #define Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 2e5 + 5;
     
    int q;
    int h, n;
    int a[N];
     
    void run() {
    	cin >> h >> n;
    	a[n + 1] = 0;
    	for(int i = 1; i <= n; i++) cin >> a[i];
    	int ans = 0;
    	for(int i = 1, j; i <= n; i = j + 1) {
    		j = i;
    		if(i != 1) {
    			++i;
    			if(a[i] != a[i - 1] - 1) {
    				++ans;
    				continue;
    			}
    		}
    		if(i > n) break;
    		j = i;
    		while(j + 1 <= n && a[j] - a[j + 1] == 1) ++j;
    		if((a[i] & 1) != (a[j] & 1) && a[j] != 1) ++ans;
    	}
    	cout << ans << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        cin >> q;
        while(q--) run();
        return 0;
    }
    

    D. AB-string

    题意:
    给出一个只含(A,B)的字符串,现在定义一个好的串是指:对于串中的每个数,都包含在一个长度大于(1)的回文串内。
    问给出的字符串中,有多少好的串。

    思路:

    • 容易发现,对于一个长度大于(2)串,其中间的数一定被包含在某个回文中;
    • 所以我们直接考虑两边的数。
    • 进一步发现,只有这样的串不满足条件:(A)或者(B)只出现一次,并且出现在两端某个位置。
    • 所以最终不合法的情况一定是“一段一段”的,可以直接压缩连续的段,统计个数然后直接算就行。

    我做法是正反扫两边来搞的,稍微复杂一点。

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    // #define Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 3e5 + 5;
     
    int n;
    char s[N];
     
    void run() {
        cin >> (s + 1);
        ll ans = 0;
        for(int i = 1, j; i < n; i = j) {
            j = i;
            while(j <= n && s[j] == s[i]) ++j;
            --j; i = j;
            while(j + 1 <= n && s[j + 1] != s[i]) ++j;
            ans += j - i;
        }
        for(int i = n, j; i > 1; i = j) {
            j = i;
            while(j >= 1 && s[j] == s[i]) --j;
            ++j; i = j;
            while(j - 1 >= 1 && s[j - 1] != s[i]) --j;
            if(i - j - 1 >= 0) ans += i - j - 1;
        }
        ans = 1ll * (n - 1) * n / 2 - ans;
        cout << ans << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        while(cin >> n) run();
        return 0;
    }
    

    E. Keyboard Purchase

    题意:
    给出一个最多由前(m)个字母组成的字符串。
    现在串的贡献就为(sum_{i=2}^{n}|pos_{s_{i-1}}-pos_{s_i}|)(pos_c)表示(c)这个字符在排列中的位置,这个排列是自己定的。
    现在就要求所有排列中最小的贡献。

    思路:

    • 一开始想的就是枚举第一个位置的数...枚举第二个位置的数...但复杂度是阶乘级别的,然后没做出来;然后将问题转化为二元组,似乎也不行...就卡住了。
    • 后来发现,直接可以二进制压缩,当二进制上面有(x)(1)时,就相当于固定了前(x)个位置,位置固定后,绝对值就很好化简了。
    • 然后枚举新添加进来的数,把绝对值拆开单独计算它的贡献,比如它和前面某些数相邻,此时他的贡献就是正的,对于其它的,他的贡献就是负的。
    • 直接做复杂度是(O(2^m*m^2))的,可以预处理一下(g(state,i))表示(state)中与(i)相邻的有多少个,转移直接利用二进制最后一位来进行转移,显然统计出来的(g(state,i))不重不漏,最终复杂度就为(O(2^m*m)了)

    关键在于状态的定义,除开一般的“存在性”的含义,还有隐性含义固定前面的位置,并且仔细思考,这样其实可以直接枚举到所有的情况,之前似乎还没碰过这种hhh,感觉很巧妙。
    详见代码:

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    // #define Local
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 2e6 + 5, M = 20;
     
    int n, m;
    char s[N];
    int cnt[M][M], num[N];
     
    int g[N][M], f[N];
    int lg2[N];
     
    int lowbit(int x) {return x & -x;}
     
    void run() {
        cin >> (s + 1);
        memset(cnt, 0, sizeof(cnt));
        memset(f, INF, sizeof(f));
        memset(num, 0, sizeof(num));
        int lim = 1 << m;
        for(int i = 2; i < 1 << m; i++) lg2[i] = lg2[i >> 1] + 1;
        for(int i = 1; i < n; i++) {
            ++cnt[s[i] - 'a'][s[i + 1] - 'a'];
            ++cnt[s[i + 1] - 'a'][s[i] - 'a'];
        }
        for(int i = 0; i < lim; i++) {
            for(int j = 0; j < m; j++) {
                if(i == 0) g[i][j] = 0;
                else g[i][j] = g[i ^ lowbit(i)][j] + cnt[j][lg2[lowbit(i)]];
            }
        }
        for(int i = 0; i < lim; i++) {
            for(int j = 0; j < m; j++) {
                if(i >> j & 1) ++num[i];
            }
        }
        f[0] = 0;
        for(int i = 0; i < lim; i++) {
            for(int j = 0; j < m; j++) {
                if(i >> j & 1) {
                    int msk1 = i ^ (1 << j);
                    int msk2 = (lim - 1) ^ i;
                    f[i] = min(f[i], f[msk1] + num[i] * (g[msk1][j] - g[msk2][j]));
                }
            }
        }
        cout << f[lim - 1] << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        while(cin >> n >> m) run();
        return 0;
    }
    

    F. The Maximum Subtree

    题意:
    求树上最大毛毛虫。

    思路:
    直接(dp)就行,一开始初始化错了改了一小时...
    感觉难点就是问题的转化?但感觉问题转化也不是很难...

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    // #define Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 3e5 + 5;
     
    int n, q;
    int ans;
    int g[N];
    struct Edge {
        int v, next;
    }e[N << 1];
     
    int head[N], tot;
    void adde(int u, int v) {
        e[tot].v = v; e[tot].next = head[u]; head[u] = tot++;
    }
     
    void dfs(int u, int fa) {
        int son = 0, mx = 0, mx2 = 0;
        for(int i = head[u]; i != -1; i = e[i].next) {
            int v = e[i].v;
            if(v == fa) continue;
            ++son;
            dfs(v, u);
            g[u] = max(g[u], g[v]);
            if(g[v] > mx) {
                mx2 = mx, mx = g[v];
            } else if(g[v] > mx2) mx2 = g[v];
        }
        if(son == 0) {
            g[u] = 1; return;
        }
        ans = max(ans, mx + mx2 + max(son - 1, 1) + (fa != 0));
        g[u] += son;
    }
     
    void run() {
        cin >> n;
        for(int i = 1; i <= n; i++) head[i] = -1, g[i] = 0;
        tot = 0;
        for(int i = 1; i < n; i++) {
            int u, v; cin >> u >> v;
            adde(u, v); adde(v, u);
        }
        ans = 0;
        dfs(1, 0);
        cout << ans << '
    ';
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        cin >> q;
        while(q--) run();
        return 0;
    }
    
  • 相关阅读:
    libevent
    STL中mem_fun和mem_fun_ref的用法
    java的awt和swing的区别于联系
    数据库流程控制的使用IF CASE LOOP LEAVE ITERETA REPEAT WHILE
    mysql的常用函数
    数据库的基本知识点
    使用myeclipse 打包并运行普通java项目
    getClass()与getName()方法
    Java中的final关键字
    基本类型包装类的常量池技术
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11644791.html
Copyright © 2011-2022 走看看