zoukankan      html  css  js  c++  java
  • Codeforces Round #696 (Div. 2) A

    A. Puzzle From the

    题意:

    (a)(b) 两个数(长度相同)相加得到 (c),对于 (c) 中的如果某一段区间上的数字相同就省略只写一个(例如:(112200) 省略为:(120))就得到了 (d)。在已知 (b) 的情况下计算一个 (a) 要求使 (d) 最大。

    思路:

    显然对于一个数越长就越大,那么 (c) 的相邻位一定是不同的。第一位一定是 (2)

    代码:
    int main() {
    
        int t; cin >> t;
        while (t --) {
            int n;
            cin >> n;
            string a = "", b;
            cin >> b;
            int len_b = b.size();
            a += '1';
            for (int i = 1; i < len_b; i ++) {
                if (b[i] + '1' == a[i - 1] + b[i - 1]) a += '0';
                else a += '1';
            }
            cout << a << endl;
        }
        return 0;
    }
    

    B. Different Divisors

    题意:

    对于 (a) 的所有因数之差大于等于 (d)。求最小的满足条件的 (a)。((a) 至少有四个因数)

    思路:

    对于一个数来说至少有两个因数那就是 (1) 和他本身。

    那么我们从 (1) 开始,找一个 (ge d+1) 的素数 (x)。在找一个 (ge x+d) 的素数 (y)。那么 (x imes y) 就是答案。

    之所以找素数是因为如果我们找的是合数,那么对于这个合数还有其他因子,那么就无法判断。

    (x imes y) 根据质因数分解为:(x^1 imes y^1)。那么就只有这四个因数,显然 (a - y ge d) 的。所以合理。

    我们可以先预处理出素数,然后二分即可。

    代码:
    const int N = 1e7;
    vector<int> primes;
    int is_prime[N];
    
    void init() {
        memset(is_prime, 0, sizeof is_prime);
        for (int i = 2; i < N; i ++) {
            if (is_prime[i] == 0) primes.pb(i);
            int len_primes = primes.size();
            for (int j = 0; j < len_primes && primes[j] * i  < N; j ++) {
                is_prime[i * primes[j]] = 1;
                if (i % primes[j] == 0) break;
            }
        }
    }
    
    
    int main() {
    
        init();
        
        int len_primes = primes.size();
    
        int t; cin >> t;
        while (t --) {
            int d; cin >> d;
            int a = lower_bound(all(primes), d + 1) - primes.begin();
            int b = lower_bound(all(primes), primes[a] + d) - primes.begin();
            ll ans = 1ll * primes[a] * primes[b];
            cout << ans << endl;
        }
        return 0;
    }
    
    

    C. Array Destruction

    题意:

    给定一个数组 (a)。初始选定一个 (x),在数组中找两个数 (a, b) 满足 (a + b = x),那么 (a,b) 就从数组中删去,并且 (x = max(a, b)),继续操作下去,问是否可以把数组中的数删光?如果可以就输出初始的 (x) 和每次删除的 (a, b)

    思路:

    显然我们可以知道对于当前的操作下选取的 (a, b) 中的较大值一定是当前数组中的最大值,只有这样才有可能删完。那么根据当前的 (x),又从数组中选出当前的最大值,那么另一个数就可以求出来。只有第一次操作的时候,由于 (x) 的未知,所以无法确定另一个数。

    由于数组的长度 (le 2 imes 10^3)。那么我们可以暴力枚举第一次选取的另一个数。复杂度为 (O(n^2))

    代码:
    const int N = 2e3 + 10;
    map<int, int> mp;
    
    int a[N];
    vector<PII> ans;
    
    int main() {
    
        int t; cin >> t;
        while (t --) {
            mp.clear();
            int n; cin >> n;
            int flag = 0;
            int m = n << 1;
            for (int i = 1; i <= m; i ++) {
                cin >> a[i];
                mp[a[i]] ++;
            }
            sort(a + 1, a + m + 1);
            mp[a[m]] --;
            for (int i = 1; i < m; i ++) {
                ans.clear();
                ans.pb({a[m], a[i]});
                int j = m - 1;
                map<int, int> tmp_map = mp;
                tmp_map[a[i]] --;
                int pre = a[m];
                while (j > 0) {
                    if (tmp_map[a[j]]) {
                        if (pre - a[j] == a[j] && tmp_map[a[j]] >= 2) {
                            tmp_map[a[j]] -= 2;
                            ans.pb({a[j], a[j]});
                            pre = a[j];
                        } else if (pre - a[j] != a[j] && tmp_map[pre - a[j]]) {
                            tmp_map[a[j]] --;
                            tmp_map[pre - a[j]] --;
                            ans.pb({a[j], pre - a[j]});
                            pre = a[j];
                        } else {
                            break;
                        }
                    }
                    j --;
                }
                if (ans.size() == n) {
                    flag = 1;
                    break;
                }
            }
            if (flag) {
                puts("YES");
                cout << ans[0].x + ans[0].y << endl;
                for (int i = 0; i < n; i ++) cout << ans[i].x << " " << ans[i].y << endl;
            } else {
                puts("NO");
            }
        }
        
        return 0;
    }
    

    D. Cleaning

    题意:

    (n) 堆石头,每次你可以让相邻位上的石头数 (-1)(前提是有石头)。你有一次特殊操作是交换两堆相邻石头。问最终能否把石头的数量都变为 (0)

    思路:

    根据题意可知,第 (x) 堆石头只能由 (x+1) 堆来清除,直至第 (n) 堆清楚完第 (n-1) 堆后刚好为 (0)

    那么 (O(n^2)) 的做法就是枚举交换的位置,然后判断是否可行即可。

    此时我们可以发现在枚举交换位置后的判断有重复的计算,所以我们可以预处理出 (l)(r) 数组,(l[i]) 代表从左往右消除到位置 (i) 上剩余的石头数,(r[i]) 代表从右往左消除到位置 (i) 上的石头数量,如果 (l[i] = r[i + 1]) 就说明不用交换就可以消除完,那么我们枚举交换的位置 (i, i + 1),只需要判断四堆石头即:(l[i - 1], a[i], a[i + 1], r[i + 2]) 是否可以消除完即可。

    注:当 (l[i] < 0),那么之后的都是不合法的了。

    代码:
    const int N = 2e5 + 10;
    
    int a[N];
    ll l[N], r[N];
    
    int main() {
    
        int t; cin >> t;
        while (t --) {
            int n; cin >> n;
            memset(l, 0, sizeof l);
            memset(r, 0, sizeof r);
            int l_flag = n + 1, r_flag = -1;
            // LNF 为无穷大
            for (int i = 1; i <= n; i ++) {
                cin >> a[i];
                if (a[i] >= l[i - 1]) l[i] = a[i] - l[i - 1];
                else l[i] = LNF / 2;
            }   
            for (int i = n; i >= 1; i --) {
                if (a[i] >= r[i + 1]) r[i] = a[i] - r[i + 1];
                else r[i] = LNF;
            }
            int flag = 0;
            // 枚举交换的位置
            for (int i = 1; i <= n - 1; i ++) {
                if (l[i] == r[i + 1]) {
                    flag = 1;
                    break;
                }
                // 交换 i 和 i + 1
                if (a[i + 1] >= l[i - 1] && a[i] >= r[i + 2] && a[i + 1] - l[i - 1] == a[i] - r[i + 2]) {
                    flag = 1;   
                    break;
                }
            }
            if (flag == 1) puts("YES");
            else puts("NO");
        }
        return 0;
    }
    
  • 相关阅读:
    Android存储数据方式(转)
    Android实现双进程守护 (转)
    Android DOM、SAX、Pull解析XML(转)
    TCP/IP和Socket的关系(转)
    Socket通信原理和实践
    [转]Android中Intent传递对象的两种方法(Serializable,Parcelable)
    内存堆和栈的区别
    hdu 1754 线段树
    hdu 1166 线段树
    zoj 3686 线段树
  • 原文地址:https://www.cnblogs.com/nonameless/p/14321699.html
Copyright © 2011-2022 走看看