Codeforces Round #651 (Div. 2)(A~D)

A. Maximum GCD

分析

  • 题意
  1. 在1~n之间选择两个不同数a,b,使得它们的gcd(a,b)比其它的任意两个数的gcd值都大
  • 思路
  1. 如果n是偶数,那gcd最大值一定是 n/2------->gcd(n,n/2)
  2. 如果n是奇数,那gcd最大值一定是(n-1)/2------>gcd(n-1,(n-1)/2)

代码

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#include<iostream>
#include<algorithm>
using namespace std;
const int mxn = 2e5 + 10;

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        int n;
        scanf("%d", &n);
        if(n % 2)
            printf("%d\n", (n - 1) / 2);
        else
            printf("%d\n", n / 2);
    }



    return 0;
}

B. GCD Compression

分析

  • 题意
    1.给我们2* n个数的序列a,刚开始我们可以从中选择两个数丢弃不用,之后在剩下的2*n-2个数中,我们要进行n-1次操作,每次操作我们我们从a中选择两个数,把这两个数的和,放入到b序列中(初始时b为空序列),问最后能否使gcd(b1,b2,…,bn-1)> 1 ?
  • 思路
  1. 既然要b 中所有元素的gcd>1,那么我们可以构造出所有元素的gcd == 2
    1. 为什么一定可以构造出呢?
    2. 因为我们考虑手中的2*n数字,如果偶数的数量为偶数个,那么奇数的数量也为偶数个,那么我们可以让所有的奇数两两组合形成一个数放入到b中,而在偶数中,我们先丢弃两个数然后让剩下的所有偶数两两组合放入到b中
    3. 如果偶数的数量是奇数个,那么奇数的数量也必然是奇数个,这个时候我们分别在偶数、奇数中各舍弃一个数字,奇数与奇数两两组合、偶数与偶数两两组合 放入到b序列中
    4. 这样就一定可以构造出所有元素的gcd==2的序列b了

代码

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#include<iostream>
#include<algorithm>
using namespace std;
const int mxn = 2e3 + 10;

vector<int> ev, od;

int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        od.clear();
        ev.clear();
        int n;
        scanf("%d", &n);
        for(int i = 1, t; i <= 2*n; i ++)
        {
            scanf("%d" ,&t);
            if(t % 2)
                od.pb(i);
            else
                ev.pb(i);
        }

        int ct = 0;
        for(int i = 0; i < od.size() / 2 * 2 && ct < n - 1; i +=2, ct ++)
        {
            printf("%d %d\n", od[i], od[i + 1]);
        }
        for(int i = 0; i < ev.size() / 2 * 2 && ct < n - 1; i += 2, ct ++)
        {
            printf("%d %d\n", ev[i], ev[i + 1]);
        }

    }



    return 0;
}


C. Number Game

分析

  • 题意
  1. 两个玩家在玩博弈数字游戏,刚开始给我们一个数n,玩家可以对这个数进行两种操作:
    1. 令n /= (n的一个奇数因子),如果n>1且没有奇数的因子的话,就不能进行该操作,
    2. 令n-=1,前提是n>1
  2. 谁先无法操作是失败
  • 思路
  1. 考虑几种必胜、必败情况:
    1. 如果n==1,我必败
    2. 如果n==2,我必胜,因可以令n-=1,之后另一个玩家就不可以操作了
    3. 如果n奇数,我必胜,我可以令n/=n,之后n1另一个玩家就无法操作了
    4. 如果n==偶数,
      1. 如果n没有奇数因子,我必败,因为我只能进行 n-=1操作,之后n变为奇数…
      2. 如果n有奇数因为,我必胜,因为我考虑如果 奇数x奇数=奇数,如果n有多个奇数因子我们令它们相乘仍为一个奇数(且是最大的奇数因子设为x),我们令n/=x,n必定变成了一个偶数且无奇数因子,这样另一个玩家只能,进行 n-=1,操作,n变为奇数,接下来我们就必胜了(在这种情况中我们要特殊考虑:n/x==2的这种情况因为,因为n变为2之后另一个玩家就可以通过 n-=1操作,n就变成了1,我们就输了
        1.所以我们要想赢的话,我们先判读n为奇数还是偶数,如果是奇数,直接出答案,如果是偶数,我们进一步讨论n是否有奇数因子(特殊考虑:n/奇数椅子==2的情况)

代码

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#include<iostream>
#include<algorithm>
using namespace std;
const int mxn = 2e3 + 10;


int main()
{
    /* fre(); */
    int T;
    scanf("%d", &T);
    while(T --)
    {
        int n;
        scanf("%d", &n);
        if(n == 1) printf("FastestFinger\n");
        else if(n == 2) printf("Ashishgup\n");
        else if(n % 2) printf("Ashishgup\n");
        else
        {
            int fg = 0;
            for(int i = 2; i * i < n; i ++)
            {
                if(n % i) continue;
                if(i % 2 && (n / i ) != 2) fg = 1;
                if((n / i) % 2 && i != 2) fg = 1;
            }
            if(fg)
                printf("Ashishgup\n");
            else
                printf("FastestFinger\n");
        }
    }

    return 0;
}

D. Odd-Even Subsequence

分析

  • 题意
  1. 给我们一个n个元素的序列a,我们可以任意从a中选择一个长度为k的子序列作为s序列,但是我们要求在所有长度为k的子序列中s序列的花费 m i n ( m a x ( s 1 , s 3.. s 2 i + 1 , m a x ( s 2 , s 4... s 2 i ) min(max(s1,s3..s_{2i+1},max(s2,s4...s_{2i}) 最小(其中2i+1、2i均<=k),求出这个最小的花费
  • 思路
  1. 因为s序列中要么是奇数位置贡献出最小的答案,要是偶数位置贡献出最小答案,我们用 二分答案,对于我们某一个二分出来的答案md,我们看能否在序列a中合理的选择一些数字(这些数字<=md),最后判断 选择的这些数字能否形成一个序列s,如果能够形成s,那么这个二分的答案就是的 ok的,,,这样一直二分下去就能得到答案了

    ①. 如果是s中奇数位置贡献答案的情况。

    1. 那么我们选择s中奇数位置的索引的数字的时候就,就要让他们都小于md,
    2. 而对于s中偶数位置的数字的选择,我们则可以随意选,但是偶数位置的数字选择的越靠前越好因为我们可以,给奇数 的选择留下更多的 选择空间,所以
    3. 当我们选择了一个s中奇数位置的数字(设为t)之后,我接着就在t后面的那个数(因为如果相邻的两个数都<=md,那么他们的贡献都是1,奇数位置选的数只能从这两个数中选择一个,当然要选择考前的了,这样给后面 留的选择空间更多),
    4. 奇数位置的数我们要选择 ( k + 1 ) / 2 (k+1)/2 个数,偶数我们要选择 k / 2 k/2 个数字(至于为什么,分别假设n为奇数、偶数带入一下就知道了)

    ②. 如果是s中偶数的位置贡献答案的情况。

    1. 我们首先我们把a中的第一个数a1,分配给s中第一个奇数位置,不论a的值是多么小,因为我们现在关注的是 偶数位置 贡献出答案的情况,接下来就是与 情况① 相同的思路了。。。。。。

代码

#include <bits/stdc++.h>
using namespace std;
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long 
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#include<iostream>
#include<algorithm>
using namespace std;
const int mxn = 2e5 + 10;
int n, k;
int ar[mxn], br[mxn];

bool judge(int md)
{
    //奇数位置贡献出最小答案
    int od = 0, ev = 0;
    for(int i = 1; i <= n; i ++)
    {
        if(ar[i] <= md)
        {
            od ++;
            if(++ i <= n) ev ++;
        }
    }
    if(od >= (k + 1) / 2 && ev >= k / 2) return true;
    //偶数位置贡献出最小答案
    od = 1, ev = 0;                     //od = 1 是因为 在偶数中产生答案的情况下,s中的第一个位置(奇数位置)选的越靠前越好,这样给 偶数位置的数的选择留下更大的选择空间 
    for(int i = 2; i <= n; i ++)
    {
        if(ar[i] <= md)
        {
            ev ++;
            if(++ i <= n) od ++;
        }
    }

    if(od >= (k + 1) / 2 && ev >= k / 2) return true;
    return false;
}


int main()
{
    /* fre(); */ 
    scanf("%d %d", &n, &k);
    for(int i = 1; i <= n; i ++)
        scanf("%d", &ar[i]), br[i] = ar[i];
    sort(br + 1, br + 1 + n);
    int l = 1, r = n, ans;
    while(l <= r)
    {
        int md = l + r >> 1;
        if(judge(br[md])) r = md - 1, ans = br[md];
        else l = md + 1;
    }

    printf("%d\n", ans);

    return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_34261446/article/details/106894807