Loading

Codeforces Round #690 (Div. 3)

头一次比赛的时候能做出6个题,最后没时间了不然就能ak了...不过这次确实简单...希望ak早日到来吧

A. Favorite Sequence

大意:

给出一个数组,要求依次输出第一个、倒数第一个、第二个、倒数第二个.....

思路:

模拟即可

#include<bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int n, t,a[N];
int main(){
    cin>>t;
    while(t--){
        cin >> n;
        for (int i = 0; i < n;i++){
            cin >> a[i];
        }
        for (int i = 0; i < n;i++){
            if(i%2==0){
                cout << a[i/2]<<' ';
            }
            else{
                cout << a[n - i/2-1]<<' ';
            }
        }
        cout << endl;
    }
    return 0;
}

B. Last Year's Substring

大意:

给出一个数字组成的字符串,问能否删掉一个连续的区间,使得最后字符串变为“2020”

思路:

直接判断2020是否在首尾两端或者是一部分在开头一部分在结尾即可

#include<bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int t, n;
int main(){
    cin >> t;
    while(t--){
        cin >> n;
        string s;
        cin >> s;
        if (s.length() < 4) cout << "NO" << endl;
        else if(s.substr(0,4)=="2020"||s.substr(n-4,n)=="2020")
            cout << "YES" << endl;
        else if((s.substr(0,1)=="2"&&s.substr(n-3,n)=="020")||(s.substr(0,3)=="202"&&s.substr(n-1,n)=="0"))
            cout << "YES" << endl;
        else if((s.substr(0,2)=="20"&&s.substr(n-2,n)=="20"))
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}

C. Unique Number

大意:

给出一个数x(\(1<=x<=50\)),问能否找到一个数,这个数的每一位都不相同,且每一位加起来的和等于x,如果有多个,输出最小的那个

思路:

直接打表判断即可

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int t, n;
int main() {
    /*
    for (int i = 1; i <= 50; i++) {
        int can = 0;
        for (LL j = 1; j <= 999999999 && can == 0; j++) {
            LL temp = j;
            int cnt[20];
            int sum = 0;
            memset(cnt, 0, sizeof cnt);
            while (temp) {
                int tt = temp % 10;
                cnt[tt]++;
                temp /= 10;
                sum += tt;
            }
            int flag = 0;
            for (int k = 0; k <= 9; k++) {
                if (cnt[k] > 1) {
                    flag = 1;
                    break;
                }
            }
            if (flag) {
                continue;
            }
            if (sum == i) {
                can = 1;
                cout << j << ',' ;
            }
        }
    }*/
    LL res[50] = {1,        2,        3,         4,       5,       6,
                  7,        8,        9,         19,      29,      39,
                  49,       59,       69,        79,      89,      189,
                  289,      389,      489,       589,     689,     789,
                  1789,     2789,     3789,      4789,    5789,    6789,
                  16789,    26789,    36789,     46789,   56789,   156789,
                  256789,   356789,   456789,    1456789, 2456789, 3456789,
                  13456789, 23456789, 123456789, -1,      -1,      -1,
                  -1,       -1};
    cin>>t;
    while(t--){
        cin >> n;
        cout << res[n - 1] << endl;
    }
    return 0;
}

D. Add to Neighbour and Remove

大意:

给出一个数组,每次操作可以选择一个数,将其加入左边或者右边的数,然后删掉这个数,问经过多少次操作可以将数组变为全部元素相等的数组。

思路:

可以想到最后的状态必然是多个区间和相等,那么直接先对原始的数组求和,然后求这个和的约数,枚举每个约数,看能否将数组划分为多个等于这个约数的区间即可

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int const N = 3e5 + 10;
int a[N];
LL sum[N];
vector<LL> yuenum;
int quchong[233];
// 试除法求约数
vector<LL> get_divisors(LL x) {
    vector<LL> res;                                // 记录答案
    for (int i = 1; i <= x / i; ++i) {             // 枚举到sqrtx(x)
        if (x % i == 0) {                          // 如果能够整除
            res.push_back(i);                      // 放入i
            if (i != x / i) res.push_back(x / i);  // x/i不等于i,也放入答案中
        }
    }
    sort(res.begin(), res.end());  // 排序
    return res;
}

int t, n;
int main() {
    cin >> t;
    while (t--) {
        cin >> n;
        LL temp = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            sum[i] = sum[i - 1] + a[i];
            temp += a[i];
        }
        yuenum = get_divisors(temp);
        LL res = 0x3f3f3f3f;
        for (int k = 0; k < yuenum.size(); k++) {
            LL pre = 0;
            int f = 1;
            for (int i = 1; i <= n; i++) {
                pre += a[i];
                if (pre == yuenum[k]) {
                    pre = 0;
                }
                if (pre > yuenum[k]) {
                    f = 0;
                    break;
                }
            }
            if (f!=0) res = min(res, n-temp/yuenum[k]);
        }
        cout<<res<<endl; 
    }
    return 0;
}

E1. Close Tuples (easy version)

大意:

建议先看E2

相比于E2,只是限定了m=3,k=2,而且不取模。

思路:

做完E2之后直接把m=3 k=2改了交了,结果wa了...仔细想想发现不需要这么麻烦,因为m很小,直接手动算组合数即可

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

LL const N = 3e5 + 10, mod = 1e18;

int  t, n, m, k;
int  a[N];
int  main() {
    cin >> t;
    while (t--) {
        cin >> n;
        m = 3;
        k = 2;
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        LL res = 0;
        sort(a, a + n);
        for (int i = 0; i < n; i++) {
            int  pos = upper_bound(a, a + n, a[i]+k) - a - 1;
            if (pos - i + 1 < m) continue;
            res += ((LL)pos - (LL)i )*((LL)pos - (LL)i -1)/2;
        }
        cout << res << endl;
    }
    return 0;
}

E2. Close Tuples (hard version)

大意:

给出n个数,以及m和k,问能找出多少组数,满足:每组里面有m个数,且这组数里面的最大值与最小值之差不大于k

思路:

先将数组排一下序,然后对于每个数,都upper_bound找一下比这个数大k的最大的数的下标pos,如果下标的差大于等于m,则答案+=\(C_{m-1}^{pos-i}\)即可,代表以这个数为最小值有多少种取法。

    #include <bits/stdc++.h>
     
    using namespace std;
     
    typedef long long LL;
     
    int const N = 3e5 + 10, mod = 1e9 + 7;
    int fact[N], infact[N];
     
     
    LL qmi(LL a, LL k, LL p) {
        LL res = 1;
        while (k) {
            if (k & 1) res = res * a % p;
            k >>= 1;
            a = a * a % p;
        }
        return res;
    }
     
    // 预处理
    void init() {
        fact[0] = infact[0] = 1;
        for (int i = 1; i < N; ++i) {
            fact[i] = (LL)fact[i - 1] * i % mod;
            infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
        }
    }
     
    int t, n, m, k, a[N];
    int main() {
        init();
        cin >> t;
        while (t--) {
            cin >> n >> m >> k;
            for (int i = 0; i < n; i++) {
                cin >> a[i];
            }
            LL res = 0;
            sort(a, a + n);
            for (int i = 0; i < n; i++) {
                int pos = upper_bound(a, a + n, a[i]+k) - a - 1;
                if (pos - i + 1 < m) continue;
                //cout << "yes" << endl;
                res += (LL)fact[pos - i ] * infact[m-1] % mod *
                       infact[pos - i + 1 - m] % mod;
                res = res % mod;
            }
            cout << res << endl;
        }
        return 0;
    }

F. The Treasure of The Segments

大意:

给出n个区间,问最少需要删去多少个区间,使得剩下的区间满足至少有一个区间和其他所有剩下的区间都相交

思路:

一开始想枚举每个区间然后算有哪些区间和它相交,写了一发发现不对,没有考虑被它包含的情况,后来发现只需要直接求和它不相交的区间有多少即可。

和区间i不相交的区间j满足:

j的右区间小于i的左区间 或者 j的左区间大于i的右区间

所以只需要两次按照端点排序,分别二分即可

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;
int t, n, temp[N];
struct node {
    int l, r, ln, rn;
} a[N];

bool cmpl(node a, node b) { return a.l < b.l; }
bool cmpr(node a, node b) { return a.r < b.r; }
int main() {
    cin >> t;
    while (t--) {
        cin >> n;
        for (int i = 0; i < n; i++) {
            cin >> a[i].l >> a[i].r;
            a[i].ln = a[i].rn = 0;
        }
        sort(a, a + n, cmpl);
        for (int i = 0; i < n; i++) {
            temp[i] = a[i].l;
        }
        for (int i = 0; i < n; i++) {
            int pos = upper_bound(temp, temp + n, a[i].r) - temp;
            a[i].rn = n-pos;
        }
        sort(a, a + n, cmpr);
        for (int i = 0; i < n; i++) {
            temp[i] = a[i].r;
        }
        for (int i = 0; i <n; i++) {
            int pos = lower_bound(temp, temp + n, a[i].l) - temp-1;
            a[i].ln = pos + 1;
        }
        int res = 0x3f3f3f3f;
        for (int i = 0; i < n; i++) {
            res = min(a[i].ln + a[i].rn, res);
        }
        cout << res << endl;
    }
    return 0;
}
posted @ 2020-12-17 02:13  dyhaohaoxuexi  阅读(96)  评论(0编辑  收藏  举报