Codeforces Round #651 (Div. 2)

31 篇文章 1 订阅
9 篇文章 0 订阅

这里写下ABCDE吧,这次思路感觉不是怎么很明确

传送门


A. Maximum GCD

主要思路:n/2即可

解题思路:
  • 由于让求1 <= x < y <= n, 求 max(gcd(x,y)), 那么如果x = k, 那么最大情况, y = 2k, 这样他们的最大公约数就为k
  • 因此最大值就是n / 2(倍数关系,二倍是最小的)
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
 
using namespace std;
 
typedef long long ll;
 
const int N = 100010, M = 200010;
 
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        int k = max(n/2,1);
        printf("%d\n",k);
    }
    return 0;
}


B. GCD Compression

主要思路:我们首先删除% 2 不是偶数的个数,然后判断下删除的数值,然后进行两两合并,让gcd == 2即可

解题思路:
  • 首先这个答案肯定是存在的
  • 然后题目中让我们求gcd > 1 即可,那我们可以想到 让gcd 至少为2即可
  • 因为要进行两两合并,那么我们最终让他们最终都是偶数,那么他们的gcd至少都为2,所以我们根据这一性质来进行求解
  • 我们首先 %2, 来计算出奇数和偶数的数目,然后如果奇数偶数的个数都是奇数,那么我们各删除一个,否则我们判断奇数偶数的个数,删除2个。
  • 然后我们存储奇数和偶数的下标,两个两个组合输出即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N = 100010, M = 200010;

int a[N];
int ans[N] ,res[N];

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        n *= 2;
        for (int i = 1; i <=  n; i++){
            scanf("%d",&a[i]);
        }
        int x = 0, y = 0;

        for (int j = 1; j <= n; j ++){
            if (a[j] % 2 == 1) x++;
            else y ++;
        }

        int xx =0 , yy = 0;

        if (x % 2 == 1){
            xx = 1;
            yy = 1;
        }
        else{
            if (x >= 2) xx = 2;
            else yy = 2;
        }

        for (int i = 1; i <= n; i++){
            if (xx && a[i] % 2 == 1){
                a[i] = 0;
                xx --;
            }
            if (yy && a[i] % 2 == 0 && a[i] != 0){
                a[i] = 0;
                yy --;
            }
        }
        int cnt1= 0, cnt2= 0;
        for (int i = 1; i <= n; i++){
            if (a[i] && a[i] % 2 == 1){
                ans[cnt1 ++] = i;
            }
            if (a[i] && a[i] % 2 == 0){
                res[cnt2 ++] = i;
            }
        }
        for (int i = 0; i < cnt1; i+= 2){
            printf("%d %d\n",ans[i],ans[i + 1]);
        }
        for (int i = 0; i < cnt2; i += 2){
            printf("%d %d\n",res[i],res[i + 1]);
        }
    }
    return 0;
}


C. Number Game

主要思路: 首先判断数值是否为奇数或者是2,如果是这样,那么Ashishgup肯定赢,否则再判断,如果是2^x 或者 该数不能被奇数除,那么FastestFinger赢,否则Ashishgup赢。

解题思路:
  • 首先题目中说明如果是奇数的话,可以除自身,如果到达1,那么将不能移动,不能移动的人算输,因此很容易得出如果n为奇数或者为2,那么先手肯定赢。
  • 接下来我们考虑2^x这种形式,它没有奇数可除,因此只能执行 - 1,那么它将变为奇数,后手赢。
  • 剩下的情况就为2^x * y,这种情势,这时的y为奇数,如果让2^x 为 2,那么肯定是不符合的,否则都符合,因此,如果符合,那么先手获胜,如果不符合后手获胜。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N = 100010, M = 200010;

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        if (n == 1){
            puts("FastestFinger");
            continue;
        }
        if (n % 2 == 1 || n == 2){
            puts("Ashishgup");
        }
        else{
            // 4 6 10 14 
            int xx = n;
            while(xx % 2 == 0) xx/=2;
            if (xx == 1){
                puts("FastestFinger");
                continue;
            }
            int  x = 0;
            for (int i = sqrt(n); i >= 2; i --){
                if (n % i == 0){
                    if ((n / i) % 2 == 0 && (n / i) != 2){
                        x ++;
                    }
                }
            }
            if (x) puts("Ashishgup");
            else puts("FastestFinger");
        }
    }
    return 0;
}


D. Odd-Even Subsequence

主要思路: 二分思想,找最大值中的最小值,也就是奇数偶数位上最大值中较小的值。那么我们直接二分,判断是否符合条件即可,这里的二分函数check十分的巧妙(看标程的)。

解题思路:
  • 首先我们1 - 1e9二分找最小值,这里的关键就是check函数。
  • check函数第一个参数为当前的数值,第二个是位置(奇偶位,0代表要进行奇数位,1代表要进行偶数位)
  • 那么只要我门奇数偶数位置上有一个符合情况,那么我们就符合条件,最终判断num >= k是否成立即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N = 200010, M = 200010;

int a[N];
int n, k;

bool check(int x, int cur){
    int num = 0;
    for (int i = 1; i <= n; i ++){
        if (!cur){
            num ++;
            cur ^= 1;
        }
        else{
            if (a[i] <= x){
                num ++;
                cur ^= 1;
            }
        }
    }
    return num >= k;
}

int binsearch(){
    int l = 1, r = 1e9;
    while(l < r){
        int mid = l + r >> 1;
        if (check(mid,1) || check(mid,0)){
            r = mid;
        }
        else{
            l = mid + 1;
        }
    }
    return l;
}

int main(){
    scanf("%d%d",&n,&k);
    for (int i = 1; i <= n; i++){
        scanf("%d",&a[i]);
    }
    int res = binsearch();
    printf("%d\n",res);
    return 0;
}


E . Binary Subsequence Rotation

主要思路: 我们要向右进行移动,那么如果我们的子序列是010101 或者 101010 的话,那么肯定是优的,那么我们尽量找出多组即可。

解题思路:
  • 首先我们需要判断不同的位置,我们以第一个字符串为准,如果第一个字符串当前位置为0,第二个为1那么,我们应该增加0开头的序列
  • 首先我们应该考虑是否有1开头的,如果有1开头的我们首先填入1开头的后面,对于1开头的我们也有2种情况,是以原本的1010作为基础的还是新建的(例如10101,1),我们首先考虑加入10101中,再考虑加入1中。
  • 如果没有,那么我们要重新创建,如果有0101这样的串那么我们在这个的基础上继续创建,如果没有,那么我们创建新的0子串
  • 对于1也是如此的操作
  • 最终判断是否有单独存在的即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

const int N = 100010, M = 200010;

int main(){
    int n;
    scanf("%d",&n);
    string st1, st2;
    cin>>st1;
    cin>>st2;
    int x = 0, y = 0, x1 = 0, x0 = 0, y1 = 0, y0 = 0;
    for (int i = 0; i < n; i ++){
    	if (st1[i] != st2[i]){
    		if (st1[i] == '0'){
    			if (x1 > 0){
    				x1 --;
    			}
    			else if (y1 > 0){
    				y1 --;
    			}
    			else if (x - x0 - y0> 0){ // 判断是否有完成的子串
    				x0 ++;
    			}
    			else{
    				y0 ++;
    				x++;
    			}
    		}
    		else{
    			if (x0 > 0){
    				x0 --;
    			}
    			else if (y0 > 0){
    				y0 --;
    			}
    			else if ((y - x1 - y1) > 0){ // 判断是否有完成的子串
    				x1 ++;
    			}
    			else{
    				y1 ++;
    				y++;
    			}
    		}
    	}
    	
    }
    if (x0 || x1 || y1 || y0) puts("-1"); // 有单独的(0 和 1的数目不相同)
    else printf("%d\n",x + y);
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值