B. GCD Compression【思维】
题意: 给出一个2n数组a,从a数组选出2(n-1),每次取两个数,其和加入b数组,使b数组构成一个n-1长且gcd(b1,b2,...,bn)>1,输出n-1对数在a数组的下标。
思路: 奇数两两配对, 偶数两两配对, gcd至少是2.
void solve(){
cin >> n;
vector<int> odd, even;
for(int i = 1; i <= 2 * n; ++ i){
cin >> mp[i];
if(mp[i] & 1) odd.push_back(i);
else even.push_back(i);
}
int cnt = 0;
if(odd.size() & 1) odd.pop_back();
for(int i = 0; i < odd.size(); i += 2){
printf("%d %d\n", odd[i], odd[i + 1]);
cnt ++;
if(cnt == n - 1) break;
}
for(int i = 0; i < even.size() && cnt < n - 1; i += 2){
printf("%d %d\n", even[i], even[i + 1]);
cnt ++;
if(cnt == n - 1) break;
}
}C. Number Game 【思维 数学 博弈】
题意:给出一个n,两个轮流进行以下两个操作中的一个最后不能操作的一方为败方,问谁为胜方。
1、n除以一个奇数因子【可以是自己】
2、n(n>1)减去1
思路: 先把这个数质因数分解。以下状态先手必胜:
- 这个数是奇数或者是2;
- 这个数中只含有一个2, 且有多于一个其他质因子【奇数的积一定是奇数,一下除到只剩一个2和一个奇数因子,对手只能除这个奇数因子,给自己留下2,必胜】;
- 这个数中含有多个2, 且有至少一个其他质因子【直接把其他的除掉,留下一个质因子只剩2的偶数,只能选择-1而留下一个奇数】
void Awin(){ puts("Ashishgup");}
void Fwin(){ puts("FastestFinger");}
void solve(){
cin >> n;
if(n == 1) Fwin();
else if(n & 1 || (n == 2)) Awin();
else{
ll even = 1, odd = 0;
int rec = n;
for(int i = 2; i <= rec / i; ++ i){
if(rec % i == 0){
while(rec % i == 0){
rec /= i;
if(i & 1) odd ++;
else even *= i;
}
}
}
if(rec > 1){
if(rec & 1) odd ++;
else even *= rec;
}
//printf("odd = %d even = %d\n", odd, even);
if((odd && even > 2) || (even == 2 && odd > 1)) Awin();
else Fwin();
}
}D - Odd-Even Subsequence【思维 二分 贪心】
题意:给出一个n个数的数组,从中挑选k个数,形成一个新的数组,定义该数组的值为min(max(s1,s3,s5...,s2,s4,s6...)),问该数组值最小为多少。
思路:考虑二分。【如果某个值凑不出来,那比他小的也一定凑不出来。】
二分的时候传入一个flag表示这次判断的是奇数位置凑还是偶数位置凑。
以奇数为例: 如果找到一个比mid小的数,就把他加入奇数组中,然后下一个立即加入偶数组【这样可以保证有尽可能多的选择给下一个奇数组】。反之亦然。
bool check(int mid, bool save){
int cnt = 0, idx = 1;
bool f = save;
for(; idx <= n; ++ idx){
if(!f) cnt ++, f = !f;
else{
if(a[idx] <= mid) cnt ++, f = !f;
}
}
return cnt >= k;
}
void solve(){
cin >> n >> k;
int maxx = 0;
for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]), maxx = max(maxx, a[i]);
int l = 0, r = maxx;
while(l < r){
int mid = l + r >> 1;
if(check(mid, 0) || check(mid, 1)) r = mid;
else l = mid + 1;
}
cout << r;
}E - Binary Subsequence Rotation【思维】
题意:给出n长两个字符数组a、b,可以取a数组的任意子序列进行顺时针旋转,sn->s1,s1->s2...。问a字符数组能否转变为b字符数组。
思路: 首先判断01是否相等。
然后把两个字符串中不等的位置单独提取出来做进一步判断。
考虑相连的1和0一定没有作用【连续重复的1还会被再转到一次,对答案没有贡献】(因为如果是1100要转成0011,取这4个转成0110,0011要两步,取两个10转也是2步)
所以答案就是判断有多少个101010...或者010101...
void solve(){
cin >> n >> s1 + 1 >> s2 + 1;
for(int i = 1; i <= n; ++ i) if(s1[i] == '1') a1 ++;
for(int i = 1; i <= n; ++ i) if(s2[i] == '1') a2 ++;
if(a1 != a2) puts("-1");
else{
int ans1 = 0, ans2 = 0, one = 0, zero = 0;
for(int i = 1; i <= n; ++ i) {
if(s1[i] == s2[i]) continue ;
tmp[++ idx] = s1[i];
}
for(int i = 1; i <= idx; ++ i){
if(tmp[i] == '1'){
if(zero > 0) zero --;
else one ++;
}else{
if(one > 0) one --;
else zero ++;
}
ans1 = max(ans1, one);
ans2 = max(ans2, zero);
}
cout << ans1 + ans2;
}
}注意最后答案是10的数量和01的数量相加而不是取最大。
考虑1001这个序列,10是一个,01是一个,one > 0的时候表示这个序列以1打头, zero > 0的时候表示这个序列以0打头。

京公网安备 11010502036488号