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序列的花費min(max(s1,s3..s2i+1,max(s2,s4...s2i)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/2k/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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章