题目
A题意:1到n中任选两个不同的数,gcd最大为大少。
解法:假设最大公约数为g,两个数不同所以两个数分别为g,2g.所以g=[(frac{n}{2})]
void solve(){
int n ;
cin >> n ;
cout << n/2 << endl;
}
B题意:给出一个2n数组a,从a数组选出2(n-1),每次取两个数,其和加入b数组,使b数组构成一个n-1长且gcd(b1,b2,...,bn)>1,输出n-1对数在a数组的下标。
解法:gcd>1,考虑b数组全为偶数必然满足条件,把a数组分成奇偶两组,奇数两两配对,偶数两两配对,一定可以至少选出n-1对数的和为偶数。
void solve(){
int n ;
cin >> n ;
vector<int>j , o;
rep(i , 1 , n*2){
cin >> a[i];
if(a[i]%2==1){
j.pb(i);
}else{
o.pb(i);
}
}
vector<pii>v;
for(int i = 1 ; i <= size(j)-1 ; i+=2){
v.pb(mp(j[i] , j[i-1]));
}
for(int i = 1 ; i <= size(o)-1 ; i+=2){
v.pb(mp(o[i] , o[i-1]));
}
for(int i = 0 ; i < n-1 ; i++){
cout << v[i].fi << " " << v[i].se << endl;
}
}
C题意:给出一个n,两个轮流进行以下两个操作中的一个最后不能操作的一方为败方,问谁为胜方。
1、n除以一个奇数因子
2、n(n>1)减去1
解法:1、如果为奇数先手赢。直接全拿走
2、质因子2只有1个,且其他质因子大于1个,则先手赢。策略:先手拿其他质因子数剩下一个,后手处于必败态
3、质因子2多于1个,且有其质他因子,则先手赢。策略:先手拿光其他质因子(一定为奇数),将大于2的偶数必败态转给了对手
4、2为先手赢
其他情况为后手胜。
void solve(){
int n ;
cin >> n ;
if(n == 1){
cout << "FastestFinger" << endl;
}else if(n == 2){
cout << "Ashishgup" << endl;
}else{
if(n % 2 == 1){
cout << "Ashishgup" << endl;
}else{
int cnt = 0 ;
while(n%2==0){
n/=2;
cnt++;
}
if(n == 1){//只有2质因子
cout << "FastestFinger" << endl;
}else{
if(cnt == 1 && !is_prime(n)){//2质因子只有1个,其他质因子有多于1个
cout << "Ashishgup" << endl;
}else if(cnt > 1){//质因子2多于1个,且有其他质因子
cout << "Ashishgup" << endl;
}else{
cout << "FastestFinger" << endl;
}
}
}
}
}
D题意:给出一个n个数的数组,从中挑选k个数,形成一个新的数组,定义该数组的值为(min(max(s_1,s_3,s_5..., s_2,s_4,s_6...))),问该数组值为最小为多少。
解法:二分答案+贪心。分两种情况,如果该最小值为奇数贡献,遍历只要符合条件(小于二分枚举值)则加入奇数下标中,下一个数如果有就加入偶数下标,判断一下奇偶数的个数是否满足条件,偶数贡献同理。
const int maxn = 2e5+9;
int a[maxn];
int n , k ;
int lenj , leno ;
bool check(int x){
int i = 1 , j = 0 , o = 0 ;
while(i <= n){
if(a[i] <= x){
j++;
if(i+1 <= n){
i += 2 ;
o++;
}else{
i++;
}
}else{
i++;
}
}
if(j >= lenj && o >= leno) return true;
i = 2 , j = 1 , o = 0 ;
while(i <= n){
if(a[i] <= x){
o++;
if(i+1 <=n){
i+=2;
j++;
}else{
i++;
}
}else{
i++;
}
}
if(j >= lenj && o >= leno) return true;
return false;
}
void solve(){
cin >> n >> k ;
lenj = (k+1)/2 , leno = k/2;
rep(i , 1 , n){
cin >> a[i];
}
int l = 1 , r = 1e9 ;
while(r > l){
int mid = (l + r) >> 1;
if(check(mid)){
r = mid ;
}else{
l = mid + 1;
}
}
cout << r << endl;
}
E题意:给出n长两个字符数组a、b,可以取a数组的任意子序列进行顺时针旋转,sn->s1,s1->s2...。问a字符数组能否转变为b字符数组。
解法:首先判断a与b中相同字符数量是否相等。不相等则输出-1.
相同的字符不需要转动,所以旋转序列不选它们,因为所选序列为0101010或1010101.
10则a数组需要向右移,01b数组需要向左移。
void solve(){
int n ;
cin >> n ;
scanf("%s%s" , a+1 , b+1);
int x = 0 , ma = 0 , mi = 0 ;
rep(i , 1 , n){
x += a[i] - '0';
x -= b[i] - '0';
ma = max(ma , x);//往a需要右移ma位
mi = min(mi , x);//b需要往左移mi位
}
int ans = ma - mi ;
if(x != 0) ans = -1;
cout << ans << endl;
}