Codeforces Round #721 (Div. 2)
A
给定一个数n,求不超过n的最大的数k使得n(&-1)&(n-2)&…&(k)=0
将n用二进制表示,例如6=110,7=111;
对于n = 6,(110)中,取最高位的1,得到一个数4(100)(最高位为1后面都为0),将其-1得3(11)为,即为答案k。(全部都是1)
显然,要使最后结果全部为0,至少存在一个数,在n的最高位为1的那位为0。
101011
011111
所以取n的最高位1,得到的数(10000…),将该数-1(11111…);
k一定小于等于这个数(1111…),才能使得最后的结果中n最高位变成0。
其次,取n的最高位1,得到的数(10000…)在[k,n]中,且能使得除最高位的1以后的其他位数变为0。
所以k为答案。
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string.h>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//#define int long long
const int maxn = 2e5 + 100;
const int mod = 1e9 + 7;
const int INF = (1 << 31) - 1;
void work() {
int n; cin >> n;
for (int i = 30; i >= 0; --i) {
if ((1 << i) <= n) {
cout << (1 << i) - 1 << '\n'; return;
}
}
}
signed main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T; cin >> T;
while (T--) {
work();
}
}
B1
给一个只包含0和1的字符串s,(初始状态为回文串,并且保证至少有一个0)
ALICE和BOB进行如下操作
1,花费0,翻转字符串,当且仅当前一次操作不是翻转且当前字符串不是回文
2,花费1,将一个0变为1。
全部字符串都为1时游戏结束,花费最少的人赢。ALICE先开始
1,如果字符串只有一个0
由于回文,ALICE只能将其变为1,ALICE输。
2,如果有偶数个0
由于初始时为回文,ALICE只能先变一个1,BOB在对称的位置变1,又形成回文,且有偶数个0,此时两人花费相同(重复2…)当最后剩两个0时,ALICE变其中一个为1,此时不为回文,BOB将其翻转,花费0,ALICE只能将另一个变为1,花费又加1,游戏结束,ALICE花费比BOB多2,ALICE输。(由于每一步ALICE别无选择,所以最优策略下BOB必赢)。(s回文,偶数0开局的人必输,且花费多另一个人2)
3,如果奇数个0
由于回文说明中间的数必定为0,此时ALICE将中间的0变为1,轮到BOB,此时字符串回文且为偶数个0,由2结论,偶数0开局的BOB必输,且花费多ALICE2,抵消ALICE开始花费的1,BOB花费比ALICE多1,(且每一步BOB别选择)ALICE必赢
#include<cmath>
#include<algorithm>
#include<string.h>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define int long long
const int maxn = 2e5 + 100;
const int mod = 1e9 + 7;
const int INF = (1 << 31) - 1;
int n, b;
ll ksm(ll a, ll b) {
a %= mod;
ll res = 1;
while (b) {
if (b & 1) {
res *= a; res %= mod;
}
a *= a; a %= mod;
b >>= 1;
}
return res;
}
void work() {
int n; cin >> n;
string s;
cin >> s;
int cnt = 0;
for (int i = 0; i < s.size(); ++i) {
if (s[i] == '0')cnt++;
}
if (cnt == 1) { cout << "BOB\n"; return; }
if (cnt % 2 == 0) {
cout << "BOB\n";
}
else cout << "ALICE\n";
}
signed main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int T; cin >> T;
while (T--) {
work();
}
}
B2
相对于B1初始s不一定为回文,其他相同。
如果s回文,同B1
如果不为回文(想办法转化为回文)
1,如果只有一个0,显然ALICE赢。
2,如果经过一次操作可以将s变为回文:
如果奇数个0
ALICE花费1将其中一个0变为1,此时s回文,0个数偶数,轮到BOB由B1(2)(s回文,偶数0开局的人必输,且花费多另一个人2)考虑ALICE开始时花费1,BOB比ALICE花费多1,(且每一步BOB别无选择)ALICE必赢。
如果偶数个0
(1)ALICE花费1将其中一个0变为1,此时s回文,0个数奇数,轮到BOB,按照B1(3)ALICE不能赢,所以ALICE不考虑这样做。
(2)ALICE花费0翻转一次,轮到BOB,此时BOB只能花费1将其中一个0变1
- 1,此时s变为回文,此时0个数奇数,轮到ALICE,按照B1(3)ALICE必赢
- 2,此时s不为回文,此时ALICE花费0继续翻转,s不为回文,BOB花费1将其中一个0变为1(每次操作后如果s不为回文,ALICE可以一直翻转,BOB则需一直花费1。重复此操作...)每一次操作BOB花费加1,ALICE花费一直为0。(一直下去ALICE赢)
如果想打破这个局面,BOB必须在某一次操作中将s变为回文
1,如果在ALICE第一次翻转之后,BOB将s变为回文,即3.(2).1 ALICE赢
2,如果在ALICE第二次翻转或之后BOB将s变为回文,则此时BOB花费比ALICE至少多2,此时轮到ALICE,s为回文,如果此时0个数为奇数,由B1(3)ALCIE赢。如果0个数为偶数,则ALICE上一次的翻转操作便不会进行,ALICE代替BOB进行此操作,此时s为回文,0个数为偶数,轮到BOB,有B1(2)s回文,偶数0开局的人必输,且花费多另一个人2,加上BOB之前的花费,显然BOB必输。3,经过大于等于2次操作可以将s变为回文
ALICE翻转,BOB花费1,此时s不为回文,ALICE可以继续翻转,BOB需花费1(继续下去…)ALICE赢
如果BOB想打破此局面,同上ALICE同样赢4.特判:初始时经过一次操作可以将s变为回文,且偶数个0。
说明s中间一定为0
情况1,ALICE花费1将不在中间的0变为1,此时s回文,0个数奇数,轮到BOB,此时只剩下一个0,BOB将其变为1,游戏结束,平局。
情况2如果ALICE将中间的0变为1,BOB翻转,ALICE将0变为1,ALICE花费2,BOB花费0,BOB赢
如果ALICE翻转,
情况3,BOB将其变为回文,ALICE将0变为1,游戏结束,平局。
情况4,BOB将不是中间的0变为1,ALICE翻转,BOB将0变为1,游戏结束,ALICE赢。
所以最优解下平局。总结除了特判平局,都是ALICE赢
#include<cmath> #include<algorithm> #include<string.h> #include<vector> #include<stack> #include<queue> using namespace std; typedef long long ll; typedef unsigned long long ull; #define int long long const int maxn = 2e5 + 100; const int mod = 1e9 + 7; const int INF = (1 << 31) - 1; int n, b; ll ksm(ll a, ll b) { a %= mod; ll res = 1; while (b) { if (b & 1) { res *= a; res %= mod; } a *= a; a %= mod; b >>= 1; } return res; } void work() { int n; cin >> n; string s; cin >> s; int cnt = 0; for (int i = 0; i < s.size(); ++i) { if (s[i] == '0')cnt++; } int tot = 0; for (int i = 0; i < s.size()/2; ++i) { if (s[i] != s[n - 1 - i])tot++; } if (tot == 0) { if (cnt == 1) { cout << "BOB\n"; return; } if (cnt % 2 == 0) { cout << "BOB\n"; } else cout << "ALICE\n"; } else if (tot == 1) { if (cnt == 1)cout << "ALICE\n"; else if (cnt == 2)cout << "DRAW\n"; else if ((cnt - 1) % 2 == 0)cout << "ALICE\n"; else cout << "ALICE\n"; } else cout << "ALICE\n"; } signed main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int T; cin >> T; while (T--) { work(); } }