Codeforces Round #690 (Div. 3) A-E2

A. Favorite Sequence
题目链接
水题,只要按题目要求输出即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
             cin.tie(NULL);\
             cout.tie(NULL);
const int N = 400;
int a[N];
main(){
    IO
    MULTICASE
    {
        int n;
        cin >> n;
        for(int i = 1; i <= n;i ++)
        {
            cin >> a[i];
        }
        int t = 1, s = n + 1;
        for(int i = 1;i <= n;i ++)
        {
            cout << a[t] << ' ';
            t = s - t;
            if(i % 2 == 0)t ++;
        }

        cout<< endl;
    }
}

B. Last Year’s Substring
题目链接
判断删去连续一段后能否变成2020,实际上考虑该字符串的头和尾能否构成2020即可,这里写的比较繁琐。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
             cin.tie(NULL);\
             cout.tie(NULL);
main(){
    IO
    MULTICASE
    {
        string str;
        int n;
        cin >> n >> str;

        int t1;
        bool isok = false;
        int len = str.size();
        if(str.substr(0, 4) == "2020")
            isok = true;
        if(str.substr(0, 3) == "202" && len - 1 >= 0 && str[len - 1] == '0')
            isok = true;
        if(str.substr(0, 2) == "20" && len - 2 >= 0 && str.substr(len - 2, 2) == "20")
            isok = true;
        if(str[0] == '2' && len - 3 >= 0 && str.substr(len - 3, 3) == "020")
            isok = true;
        if(len - 4 >= 0 && str.substr(len - 4, 4) == "2020")
            isok = true;

        if(isok)cout << "YES";
        else cout << "NO";
        cout << endl;
    }
}

C. Unique Number
题目链接
x < 10 x<10 x<10时,直接输出 x x x即可。
x ≥ 10 x≥10 x10时,我们可以列出几项得到规律。

xs
1019
1129
1789
18189
24789
251789

规律便是先将第一位不断加 1 1 1,等第一位与第二位相同时再在最前面插入一个 1 1 1
注意到当 x > 45 x>45 x>45时,我们无法求出这个数,编程即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
             cin.tie(NULL);\
             cout.tie(NULL);
main(){
    IO
    MULTICASE
    {
        int x;
        cin >> x;
        if(x <= 9)
            cout << x << endl;
        else
        {
            int t = 1;
            if(x > 45)
            {
                cout << -1 << endl;
                continue;
            }
            set<int> st;
            st.insert(9);
            x -= 9;
            while(x --)
            {
                if(st.count(t))t = 1;
                if(st.count(t - 1))
                    st.erase(t - 1);

                st.insert(t);
                t ++;
            }
            for(auto i : st)
                cout << i;
            cout << endl;
        }
    }
}

D. Add to Neighbour and Remove
题目链接
这道题让我想了20分钟左右,想出来了一个比较巧妙的方法。
要使数列中的元素相同,他们的和就一定能被合并后的数组中的每一项整除(当然,合并后的数组的每一项都相同),我们就可以先将它们的和求出,然后对它求出所有的因数,时间复杂度约为 O ( ∑ a i ) O(\sqrt{∑a_i}) O(ai ),考虑到 a i ≤ 1 e 5 , ∑ n ≤ 3000 a_i≤1e5,∑n≤3000 ai1e5,n3000,最坏情况下大概做 2 e 4 2e4 2e4次左右的判断。
求出所有因子后,我们可以将他们从小到大排个序,将每一个因子作为合并后数组中的每一项的和,对于每一个因子,遍历数组后我们就可以判断是否能够组成将这个因子作为每一项的数列。这里的时间复杂度约为 O ( n l o g n ) O(nlogn) O(nlogn)
我们就可以较为快捷地得出这个问题的答案。
由于 ∑ n ≤ 3000 ∑n≤3000 n3000,我们同时也可以用 O ( n 2 ) O(n^2) O(n2)的较为暴力的方法得出问题的解,枚举将前 i i i( i ∈ [ 1 , n ] i∈[1,n] i[1,n])项合并成一项作为合并后数列的一项,之后判断也可。

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
             cin.tie(NULL);\
             cout.tie(NULL);
#define int long long
const int N = 3030;
int a[N];
main(){
    IO
    MULTICASE
    {
        int n;
        cin >> n;
        for(int i = 1;i <= n;i ++)
            cin >> a[i];
        int ans = accumulate(a + 1, a + n + 1, 0);

        vector<int> v;
        for(int i = 1; i * i <= ans;i ++)
        {
            if(ans % i == 0)
            {
                v.pb(i);
                if(i * i != ans)
                    v.pb(ans / i);
            }
        }
        sort(v.begin(), v.end());
        bool ok = 1, done = 0;
        for(int i = 0;i < v.size() ;i ++)
        {

            int sum = 0;
            ok = 1;
            for(int j = 1;j <= n;j ++)
            {
                sum += a[j];
                if(sum == v[i])sum = 0;
                if(sum > v[i])
                {
                    ok = false;
                    break;
                }
            }
            if(ok)
            {
                cout << n - ans / v[i] << endl;
                done = 1;
                break;
            }
        }
        if(!done)
            cout << n - 1 << endl;
    }
}

E1. Close Tuples (easy version)
题目链接
一个较为简单的组合数问题,由于题目中数组的位置对答案产生不了影响,我们就可以较为快捷地先将数组从小到大排个序,然后从第三个位置开始,用lower_bound来找出该值-2的那个下标最小的位置,设他们的间距为 x x x,则有
s u m = s u m + x × ( x − 1 ) / 2 sum=sum+x×(x-1)/2 sum=sum+x×(x1)/2
即可。

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define int long long
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
             cin.tie(NULL);\
             cout.tie(NULL);
const int N = 3030;
int a[N];
main(){
    IO
    MULTICASE
    {
        int n;
        cin >> n;
        for(int i = 1;i <= n;i ++)
        {
            cin >> a[i];
        }
        int ans = 0;
        sort(a + 1, a + n + 1);
        for(int i = 3;i <= n;i ++)
        {
            int x = lower_bound(a + 1, a + n + 1, a[i] - 2) - a;
            if(i - x < 2)continue;
            ans += (i - x - 1) * (i - x) / 2;
        }
        cout << ans << '\n';
    }
}

E2. Close Tuples (hard version)
题目链接
题目大致跟E1差不多。
考虑到 m ≤ 100 m≤100 m100,我们可以建立一个宽度为100+的杨辉三角。当然也可以预处理阶乘来求得组合数,设他们的间距为 x x x,公式即为 a n s = ( a n s + ( x m − 1 ) ) m o d    1 e 9 + 7 ans = (ans + \tbinom{x}{m-1})\mod 1e9+7 ans=(ans+(m1x))mod1e9+7
编程得:

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define int long long
#define MULTICASE int _;cin >> _;while(_ --)
#define IO ios::sync_with_stdio(false);\
             cin.tie(NULL);\
             cout.tie(NULL);
#define mod 1000000007
const int N = 200200;
int A[N];
int B[N];

//大佬的模板 QAQ
int Ext_Gcd(int a, int b, int &x, int &y)
{
    if(b==0){
        x=1;
        y=0;
        return a;
    }
    int d = Ext_Gcd(b, a%b, y, x);
    y-=a/b*x;
    return d;
}

int Inv(int a, int n)
{
    int x,y;
    int d = Ext_Gcd(a,n,x,y);
    if(d == 1)
        return ((x%n)+n)%n;
    return -1;
}

int C(int a, int b)
{
    if(a < b)
        return 0;
    return (A[a] * B[b] %mod)*B[a-b]%mod;
}
void get()
{
    for(int i=0;i< N;i++)
        B[i] = Inv(A[i],mod);
}

void Init()
{
    A[0] = 1;
    for(int i=1; i<=N; i++){
        A[i] = (A[i - 1] * i ) % mod;
    }
    get();
}
int a[N];
main(){
    IO

    Init();
    MULTICASE
    {
        int n, m, k;
        cin >> n >> m >> k;
        for(int i = 1;i <= n;i ++)
            cin >> a[i];
        sort(a + 1, a + n + 1);

        int ans = 0;
        for(int i = m;i <= n;i ++)
        {
            int x = lower_bound(a + 1, a + n + 1, a[i] - k) - a;
            if(i - x < m - 1)continue;
            ans = (C(i - x, m - 1) + ans) % mod;
        }

        cout << ans << '\n';
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值