[Codeforce刷题1]

A. 二进制热身

https://codeforces.com/contest/2108/problem/A

每次测试的时间限制:1 秒钟
每次测试的内存限制:256 兆字节
输入:标准输入
输出:标准输出

对于长度为 n n n ∗ ^{\text{∗}} 的排列 p p p,我们定义了函数:
f ( p ) = ∑ i = 1 n ∣ p i − i ∣ f(p) = \sum_{i=1}^{n} \lvert p_i - i \rvert f(p)=i=1npii
给你一个数字 n n n。你需要计算当考虑从 1 1 1 n n n 的所有可能排列时,函数 f ( p ) f(p) f(p) 可以取多少个不同的**值。

∗ ^{\text{∗}} 长度为 n n n 的排列是由 n n n 个不同的整数组成的数组,这些整数从 1 1 1 n n n 按任意顺序排列。例如, [ 2 , 3 , 1 , 5 , 4 ] [2,3,1,5,4] [2,3,1,5,4] 是一个排列,但 [ 1 , 2 , 2 ] [1,2,2] [1,2,2] 不是一个排列( 2 2 2 在数组中出现了两次), [ 1 , 3 , 4 ] [1,3,4] [1,3,4] 也不是一个排列( n = 3 n=3 n=3,但数组中有 4 4 4)。

输入

每个测试包含多个测试用例。第一行包含测试用例的数量 t t t ( 1 ≤ t ≤ 100 1 \le t \le 100 1t100)。测试用例说明如下。

每个测试用例的第一行都包含一个整数 n n n ( 1 ≤ n ≤ 500 1 \leq n \leq 500 1n500) —— 排列组合中的数字个数。

输出

对于每个测试用例,输出一个整数 —— 在给定的排列长度下,函数 f ( p ) f(p) f(p) 的不同值的个数。

AC Code
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

void solve(){
    int n;
    cin >> n;
    if (n == 1) {
        cout << "1\n";
        return;
    }
    ll max_f = 0;
    //1-max_f内所有偶数个数
    for (int i = 1; i <= n; i++) {
        max_f += abs(n - i + 1 - i);
    }
    if (n == 2) {
        cout << "2\n";
    } else {
        cout << (max_f / 2) + 1 << "\n";
    }
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    
    int t = 1;
    cin >> t;
    while(t--){
        solve();
    }
    return 0;
}

B.SUMdamental 分解

https://codeforces.com/contest/2108/problem/B

每次测试的时间限制: 1 秒
每次测试的内存限制: 256 兆字节
输入: 标准输入
输出: 标准输出

问题描述

在你最近的一次生日上,你最好的朋友莫里斯给了你一对数字 n n n x x x,并要求你构造一个长度为 n n n 的正数数组 a a a,使得:
a 1 ⊕ a 2 ⊕ ⋯ ⊕ a n = x a_1 \oplus a_2 \oplus \cdots \oplus a_n = x a1a2an=x
⊕ \oplus 表示按位异或运算)
这个任务对你来说似乎太简单了,因此你决定给莫里斯一个回礼:在所有满足条件的数组中,构造一个元素之和最小的数组。由于直接写出数组太费时间,你只需要计算并输出这个最小和。

输入格式

每个测试包含多个测试用例。第一行包含测试用例的数量 t t t ( 1 ≤ t ≤ 1 0 4 1 \leq t \leq 10^4 1t104)。

每个测试用例由一行组成,包含两个整数 n n n x x x ( 1 ≤ n ≤ 1 0 9 1 \leq n \leq 10^9 1n109, 0 ≤ x ≤ 1 0 9 0 \leq x \leq 10^9 0x109)。

输出格式

对于每个测试用例,输出满足条件数组的最小元素和。如果没有这样的数组存在,输出 − 1 -1 1

解题思路

特殊情况处理

  1. n = 1 n=1 n=1 x = 0 x=0 x=0

    • 无法构造满足条件的数组,因为唯一的元素必须是正数,而任何正数的异或结果都不可能是0
    • 输出 − 1 -1 1
  2. x = 0 x=0 x=0

    • 需要构造异或结果为0的数组
    • 如果 n n n 是偶数:
      • 可以构造数组 [ 1 , 1 , . . . , 1 ] [1, 1, ..., 1] [1,1,...,1] n n n 个1)
      • 因为 1 ⊕ 1 = 0 1 \oplus 1 = 0 11=0,且 n n n 个1的异或结果为0
      • 和为 n n n
    • 如果 n n n 是奇数:
      • 需要额外增加两个元素(如2和3)
      • 因为奇数个1的异或结果为1
      • 和为 n + 3 n + 3 n+3

一般情况处理

  1. 计算 x x x的二进制中1的个数( p c pc pc

    • 使用__builtin_popcount(x)计算
  2. 如果 c n t ≥ n cnt \geq n cntn

    • 可以直接输出 x x x
    • 因为可以用 x x x作为其中一个元素,其余用1填充
  3. 构造最小和数组

    • 初始化答案 a n s = 0 ans = 0 ans=0
    • 特殊情况处理:
      • 如果 x = 1 x=1 x=1 n n n是偶数,需要额外加2
    • n n n中减去 c n t cnt cnt(因为 x x x贡献了 c n t cnt cnt个1)
    • 处理剩余的 n n n
      • 每次处理2个元素(加2到 a n s ans ans,减2从 n n n
      • 如果最后剩下1个元素( n = 1 n=1 n=1),再加2
    • 最终结果为 a n s + x ans + x ans+x
AC Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

void solve() {
    ll n, x;
    cin >> n >> x;
    if (n==1 && x==0) {
        cout << -1 << "\n";
        return;
    }
    if (x==0) {
        if (n%2==0) {
            cout << n << "\n";
        } else {
            cout << n+3 << "\n";
        }
        return;
    }
    ll cnt=__builtin_popcount(x);
    if (cnt>=n) {
        cout << x << "\n";
        return;
    }
    ll ans=0;
    if (x==1 && n%2==0) {
        ans+=2;
    }
    n-=cnt;
    while (n>=2) {
        ans+=2;
        n-=2;
    }
    if (n==1) {
        ans+=2;
    }
    cout << ans+x << "\n";
}
  
int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    
    int t = 1;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Almond_s

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

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

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

打赏作者

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

抵扣说明:

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

余额充值