Codeforces Round 919 (Div. 2)

Codeforces Round 919 (Div. 2)

A-Satisfying Constraints

模拟

记录上下界,begin、end

如果发现有一次begin>end 直接输出0

或者 end<begin 也输出0

ans = end-begin+1

然后记录每一个不能等于的点到vector,然后遍历vector

如果存在一个点 x ∈ [ b e g i n , e n d ] x\in[begin,end] x[begin,end]

ans–

#include<bits/stdc++.h>
   
using namespace std;
#define  ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr) 


const int N = 1e6 + 7;
typedef long long ll;


int main() {
   
    int t;
    cin >> t;

    while (t--) {
        int n;
        cin >> n;
        ll begin=0, end=1e9;
        vector<ll> v;
        bool is_yes = 1;
        for (int i = 1; i <= n; i++) {
            int a; ll x;
            cin >> a >> x;
            if (a == 1) {
                if(x<=end)
                begin = max(begin,x);
                else{

                    is_yes=0;
                
                }
            }
            else if (a == 2) {
                if(x>=begin)
                end = min(end,x);
                else {
                   
                    is_yes = 0;
                   
                }
            }
            else {
                v.push_back(x);
            }

        }
        if (is_yes == 0){
            cout<<0<<endl;
            continue;
        }
        ll ans = end - begin+1;
        for (int i = 0; i < v.size(); i++) {
            if (v[i] <= end and v[i] >= begin)ans--;
        }
        cout << ans << endl;
    }
    
}

B-Summation Game

贪心,枚举

先将数组排序,然后枚举爱丽丝要消除的元素个数。

预处理出前缀和 sum

和后缀和 nxt[i]

如果爱丽丝要消除j个元素(必然从最大的开始消除),那么消除掉的元素之和:nxt[n-j]

然后鲍勃只需要从最大的开始,选x个,使其乘上-1

也就是减去 2倍的 nxt[n-j-x]-nxt[n-j]

注意到,如果不满x个,那么我们就选剩下的所有: sum-nxt[n-j]

答案就是 : sum - min( 2nxt[n-j-x]-nxt[n-j] )

只要枚举j 使2nxt[n-j-x]-nxt[n-j] 最小即可

(一开始wa了一发,后面都改成longlong就过了,不开longlong见祖宗啊)

#include<bits/stdc++.h>
   
using namespace std;
#define  ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr) 


const int N = 1e9 + 7;
typedef long long ll;


int main() {
   
    int t;
    cin >> t;

    while (t--) {
        int n, k, x;
        cin>>n>>k>>x;
        
        vector<ll> a;
        vector<ll> nxt(n + 2);

        ll sum = 0;//前缀和
        
        for (int i = 0; i < n; i++) {
            int temp;
            cin >> temp;
            sum += temp;

            a.push_back(temp);
        }

        sort(a.begin(), a.end());//排序

        for (int i = a.size()-1; i >= 0; i--) {//后缀和
            nxt[i] = nxt[i + 1] + a[i];
        }

        ll ans = 0,bns=0;
        ll cnt=N;
        
        for (int i = 0; i <= k; i++) {//枚举k

            if (n - i >= 0) {
                 ans= nxt[n-i]; //移掉的
                 
                 if(n-i-x>=0){
                     bns=nxt[n-i-x]-nxt[n-i];//如果移去之后,还有大于等于x个元素,记录最后x个元素
                 }
                 else{ //不足x个元素
                     bns=sum-nxt[n-i]; //剩下的元素就是总和-移去的元素
                 }
                 
                 cnt=min(cnt,2*bns+ans);
            }

        }
        
        cout << sum-cnt << endl;
    }
}

C-Partitioning the Array

数学、gcd、枚举

第一:

题目要我们将 a i . . . a n a_i...a_n ai...an划分为为k段。

那么说明 k 是 n的因数

第二:

我们需要找到m,使得每一段的数,分别对m取模的结果是一 一对应的

也就是

(ps:$ \equiv$ 是模意义下的等号,表示左右两边模以m相等,也就是同余)

  • a 1 ≡   a 1 + k ( m o d   m ) a_1\equiv\ a_{1+k}(mod\ m) a1 a1+k(mod m)
  • a 2 ≡   a 2 + k ( m o d   m ) a_2\equiv\ a_{2+k}(mod\ m) a2 a2+k(mod m)
  • a 3 ≡   a 3 + k ( m o d   m ) a_3\equiv\ a_{3+k}(mod\ m) a3 a3+k(mod m)
  • a 1 + k ≡   a 1 + k + k ( m o d   m ) a_{1+k}\equiv\ a_{1+k+k}(mod\ m) a1+k a1+k+k(mod m)
  • a 2 + k ≡   a 2 + k + k ( m o d   m ) a_{2+k}\equiv\ a_{2+k+k}(mod\ m) a2+k a2+k+k(mod m)
  • a n − k ≡   a n ( m o d   m ) a_{n-k}\equiv\ a_{n}(mod\ m) ank an(mod m)

而对于任意的: a i ≡   a i + k ( m o d   m ) a_i\equiv\ a_{i+k}(mod\ m) ai ai+k(mod m)

等价于 ∣ a 1 − a 1 + k ∣ ≡   0 ( m o d   m ) |a_1-a_{1+k}|\equiv\ 0 (mod\ m) a1a1+k 0(mod m)

(这个转换很常用)

等价于:m是 ∣ a 1 − a 1 + k ∣ |a_1-a_{1+k}| a1a1+k的一个因子

显然,要找到一个m,使之满足上面的所有式子,那么m必然是它们的最大公约数。

$ gcd(|a_{1+k}-a_1|,|a_{2+k}-a_2|…,|a_{n}-a_{n-k}||)$

求多个数的最大公约数,只需要两两求即可,因为最大公约数满足结合律。

#include<bits/stdc++.h>
   
using namespace std;
#define  ios ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr) 


const int N = 1e6 + 7;
typedef long long ll;

int __gcd(int a, int b) {
    return b ?  __gcd(b, a % b) : a ;
}

int main() {
   
    int t;
    cin >> t;

    while (t--) {
        int n;
        cin >> n;
        vector<int> v;
        for (int i = 1; i <= n; i++) {
            int temp;
            cin >> temp;
            v.push_back(temp);
        }

        ll ans = 0;
        for (int i = 1; i  <= n; i++) {

            if (n % i == 0) {

                int g = 0;
                for (int j = 0; j < n - i; j++) {
                    g = __gcd(g, abs(v[j+i]-v[j]));
                }
                if (g != 1)ans++; //当g==0时,说明,v[j+1]=v[j],也就是每一项都相同

            }
        }
        cout << ans << endl;

    }
       
}

0;
for (int j = 0; j < n - i; j++) {
g = __gcd(g, abs(v[j+i]-v[j]));
}
if (g != 1)ans++; //当g==0时,说明,v[j+1]=v[j],也就是每一项都相同

        }
    }
    cout << ans << endl;

}

}


  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

louisdlee.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值