A. Maximum GCD
分析
- 题意
- 在1~n之间选择两个不同数a,b,使得它们的gcd(a,b)比其它的任意两个数的gcd值都大
- 思路
- 如果n是偶数,那gcd最大值一定是 n/2------->gcd(n,n/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 ? - 思路
- 既然要b 中所有元素的gcd>1,那么我们可以构造出所有元素的gcd == 2
- 为什么一定可以构造出呢?
- 因为我们考虑手中的2*n数字,如果偶数的数量为偶数个,那么奇数的数量也为偶数个,那么我们可以让所有的奇数两两组合形成一个数放入到b中,而在偶数中,我们先丢弃两个数然后让剩下的所有偶数两两组合放入到b中
- 如果偶数的数量是奇数个,那么奇数的数量也必然是奇数个,这个时候我们分别在偶数、奇数中各舍弃一个数字,奇数与奇数两两组合、偶数与偶数两两组合 放入到b序列中
- 这样就一定可以构造出所有元素的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
分析
- 题意
- 两个玩家在玩博弈数字游戏,刚开始给我们一个数n,玩家可以对这个数进行两种操作:
- 令n /= (n的一个奇数因子),如果n>1且没有奇数的因子的话,就不能进行该操作,
- 令n-=1,前提是n>1
- 谁先无法操作是失败
- 思路
- 考虑几种必胜、必败情况:
- 如果n==1,我必败
- 如果n==2,我必胜,因可以令n-=1,之后另一个玩家就不可以操作了
- 如果n奇数,我必胜,我可以令n/=n,之后n1另一个玩家就无法操作了
- 如果n==偶数,
- 如果n没有奇数因子,我必败,因为我只能进行 n-=1操作,之后n变为奇数…
- 如果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
分析
- 题意
- 给我们一个n个元素的序列a,我们可以任意从a中选择一个长度为k的子序列作为s序列,但是我们要求在所有长度为k的子序列中s序列的花费 最小(其中2i+1、2i均<=k),求出这个最小的花费
- 思路
-
因为s序列中要么是奇数位置贡献出最小的答案,要是偶数位置贡献出最小答案,我们用 二分答案,对于我们某一个二分出来的答案md,我们看能否在序列a中合理的选择一些数字(这些数字<=md),最后判断 选择的这些数字能否形成一个序列s,如果能够形成s,那么这个二分的答案就是的 ok的,,,这样一直二分下去就能得到答案了
①. 如果是s中奇数位置贡献答案的情况。
- 那么我们选择s中奇数位置的索引的数字的时候就,就要让他们都小于md,
- 而对于s中偶数位置的数字的选择,我们则可以随意选,但是偶数位置的数字选择的越靠前越好因为我们可以,给奇数 的选择留下更多的 选择空间,所以
- 当我们选择了一个s中奇数位置的数字(设为t)之后,我接着就在t后面的那个数(因为如果相邻的两个数都<=md,那么他们的贡献都是1,奇数位置选的数只能从这两个数中选择一个,当然要选择考前的了,这样给后面 留的选择空间更多),
- 奇数位置的数我们要选择 个数,偶数我们要选择 个数字(至于为什么,分别假设n为奇数、偶数带入一下就知道了)
②. 如果是s中偶数的位置贡献答案的情况。
- 我们首先我们把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;
}