07_07_暑期个人赛3

A. Row

时间:2024-07-08

原题:Codeforces Round 484 (Div. 2) A. Row

题意

给一串字符串有01组成,1边上不能有1,0边上不能没有1,如果满足输出yes

思路

就,一个一个遍历过来,写这题主要因为需要看清题目,注意如果只有一个“0”需要输出no,因为没有1

A. Alice and Bob

时间:2024-07-08

原题:Codeforces Round 201 (Div. 1) A. Alice and Bob

题意

给一个正整数序列 \(Arr\) ,每次AB需要取其中的两个数字,使得 \(|x_i-x_j|\notin Arr\) ,然后加入其中,输出赢家

思路

一开始以为是看范围内的没被使用过的整数个数,然后发现在2的时候会出问题

当时完全没有思路,所以用上了一直没用过的对拍器

发现是看范围内gcd的公倍数的个数,调了许久才发现。。。

D. Ehab the Xorcist

时间:2024-07-08

原题:Codeforces Round 628 (Div. 2) D. Ehab the Xorcist

题意

给两个数 \(u\)\(v\) ,需要求一个最短数组\(Arr\),使所有的 \(x\) 相加等于 \(v\) ,异或起来等于 \(u\)\(x \in Arr\)

思路

首先尝试几次,发现最短数组的长度要么是2要么是3,然后寻找导致不同的原因

发现的做题思路是先获取 \(dif=v-u\) ,先将 \(dif\) 除2(除不了2说明不行)

所以最短数组要么是3,就是 \(u\) 本身和两个 \(dif/2\)

要么是2,就是 \(dif/2\) 的所有1位置在\(u\)的对应位置上都为0,那么答案就是 \(u+dif/2\)\(dif/2\)

我觉得这题本质上是考对位数处理的代码能力,和一些对数字的敏感度

代码

int u, v;
int difdig[65];
int udig[65];
void solve() {
    cin >> u >> v;
	
    if (u == 0 && v == 0) {
        cout << 0 << endl;
        return;
    }

    if (u == v) {
        cout << 1 << endl << u << endl;
        return;
    }
    if (u > v || (v - u) % 2 == 1) {
        cout << -1 << endl;
        return;
    }
    
	//tdif和tu临时记录,用于后面输出答案
    int dif = (v - u) / 2;
    int tdif = dif / 2, tu = u;
    int index = 0;//index指向二进制的当前位置
	//先将dif的所有位数存好
    while (dif) {
        if (dif % 2)difdig[index] = 1;
        else difdig[index] = 0;
        index++;
        dif /= 2;
    }
	//再将u的所有位数存好
    index = 0;
    while (u) {
        if (u % 2)udig[index] = 1;
        else udig[index] = 0;
        index++;
        u /= 2;
    }
    //对比,如果有重就输出
    for (int i = 0; i < 65; i++) {
        if (difdig[i] == 1 && udig[i] == 1) {
            cout << 3 << endl << tu << " " << tdif  << " " << tdif  << endl;
            return;
        }
    }
    cout << 2 << endl << tu + tdif  << " " << tdif  << endl;

}

C. Match Points

时间:2024-07-08

原题:Educational Codeforces Round 64 (Rated for Div. 2) C. Match Points

题意

给正整数序列 \(Arr\) ,数字 \(z\) ,每次选两个数使差值 \(dif \ge z\) ,问最多几组数

思路

本题需要理解的较为透彻,对数字的把握比较清晰才行

首先排序是一定的,有几种思路一般,第一种是相邻的数相加,但是是错的

第二种是第一种的延伸,双指针从前往后,但是我会超时。。。

第三种二分,从第一位和二分的位置开始往后一一比对

但是当时对如何二分没有思路,现在明白了。。

就是说,假定有20个数字,此时mid=15,那么如果1到5能跟15到19完全匹配成功

说明mid大了,如果mid=10,但是在第i=8,j=18时不匹配,说明mid小了

简单理解就是这样

代码

/* 1与n-pos+1匹配,pos表示中间的起始位置 */
bool check(int pos) {
    for (int i = 0; i < pos; i++) {
        if (arr[n - pos + i] - arr[i] >= z)
            continue;
        return false;
    }
    return true;
}


void solve() {
    cin >> n >> z;
    rep(ii, 0, n) {
        cin >> arr[ii];
    }
    sort(arr, arr + n);
    int ans = 0;
    int l = 0, r = n - 1;
    while (l <= r) {
        int mid = l + r >> 1;
        //如果能匹配,将中心往右
        if (check(mid)) {
            l = mid + 1;
            ans = mid;
        }
        else {
            r = mid - 1;
        }
    }
    //注意有时候mid会较大,需要判断范围
    //因为答案其实是max(n-mid,mid-0) 这里的ans只是记录的mid
    cout << (ans > n / 2 ? n / 2 : ans) << endl;
}
posted @ 2024-07-08 10:13  lulaalu  阅读(1)  评论(0编辑  收藏  举报