对于先手只要不是一次就会取完的1 * 1矩阵,总有获胜办法
#include
using namespace std;
#define MUT
#define FIO
#define INF 0x3f3f3f3f
void solve();
int main(){
int T = 1;
#ifdef MUTT
cin >> T;
#endif
#ifdef FIO
cin.sync_with_stdio(0);
cin.tie(0);
#endif
while(T--){
solve();
}
return 0;
}
void solve(){
int n, m;
cin >> n >> m;
if(n == 1 && m == 1){
cout << "Walk Alone";
}
else{
cout << "Kelin";
}
}
我们注意到,其实每次获胜只会让总额增长1,所以就是要获胜m场,两场之间输的次数不能超过目前本金的二进制最高位1的位数,然后相乘即可。
#include
using namespace std;
#define MUT
#define FIO
#define INF 0x3f3f3f3f
#define mod 998244353
#define int long long
void solve();
int qpow(int a, int b) {
int ans = 1, base = a;
while (b) {
if (b & 1) ans = ans * base % mod;
base = base * base % mod;
b >>= 1;
}
return ans % mod;
}
signed main() {
int T = 1;
#ifdef MUTT
// cin >> T;
#endif
#ifdef FIO
cin.sync_with_stdio(0);
cin.tie(0);
#endif
// T = 1;
while (T--) {
solve();
}
return 0;
}
void solve() {
int n, m;
cin >> n >> m;
int ans = 1;
int res = n + m;
int r, l;
for (int j = 0; j <= 32; j++) {
if (((1 << (j + 1)) - 1) > n) {
l = j;
break;
}
}
for (int j = 0; j <= 32; j++) {
if (((1 << (j + 1)) - 1) > res) {
r = j;
break;
}
}
// cout << l << " " << r << "\n";
for (int i = l; i <= r; i++) {
int x = (1 << i + 1) - 1;
int j, tmp = 0, temp = 1;
for (j = 0; j <= 32; j++) {
tmp += temp;
temp *= 2;
if (tmp > n) break;
}
// cout << j << "\n";
int lose = j;
int k = (1 - qpow(1 << lose, mod - 2) + mod) % mod;
int y = min(x, res) - n;
// cout << y << "\n";
ans *= qpow(k, y);
ans %= mod;
// cout << n << "\n";
n += y;
}
cout << ans << "\n";
}
我们可以bfs先搜一下到最短路径之前可以走多少步,然后我们贪心的思考,对于影响后续结点只有1的点进行增点,否则不增点。
#include
using namespace std;
#define MUT
#define FIO
#define INF 0x3f3f3f3f
#define mod 998244353
#define int long long
const int N = 2e5 + 5;
int ans;
void solve();
vector ve[N];
int dis[N];
vector> edg;
signed main() {
int T = 1;
#ifdef MUTT
// cin >> T;
#endif
#ifdef FIO
cin.sync_with_stdio(0);
cin.tie(0);
#endif
T = 1;
while (T--) {
solve();
}
return 0;
}
void bfs(int st){
queue q;
q.push(st);
for(int i = 0;i < N;i++){
dis[i] = INF;
}
dis[st] = 0;
while(q.size()){
int u = q.front();
q.pop();
int d = dis[u];
for(int v:ve[u]){
if(d + 1 < dis[v]){
dis[v] = d + 1;
q.push(v);
}
}
}
}
void solve() {
int n, m, k;
cin >> n >> m >> k;
for(int i = 1;i <= m;i ++) {
int x, y;
cin >> x >> y;
ve[x].push_back(y);
ve[y].push_back(x);
edg.push_back(make_pair(x, y));
}
bfs(1);
for(int i = 1;i <= n;i++){
if(dis[i] <= k)ans++;
}
for(int i = 2;i <= n;i++){
if(dis[i] != INF && ve[i].size() == 1 && dis[i] <= k){
ans += k - dis[i];
}
}
for(auto [x,y]:edg){
if(dis[x] == dis[y] && dis[x] <= k){
ans += 2 * (k - dis[x]);
}
}
for(int i = 2;i <= n;i++){
int le1 = 0;
for(int v:ve[i]){
if(dis[v] == dis[i] - 1){
le1++;
}
}
if(le1 >= 2 && dis[i] <= k){
ans += (2 * (k - dis[i]) + 1) * (le1 - 1);
}
}
cout << ans;
}
一眼exgcd,赛时卡住的问题在于怎么样取最小,其实列出方程就是ax+by=k,其中如果x,y是正数,则需要花费乘以2的操作数(倒入再倒出),负数可以减一(最后一次保留在杯子中不倒出),然后求通解即可。
#include
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair PII;
int n, a, b;
int exgcd(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
int g = exgcd(b, a % b, x, y);
int t = x;
x = y;
y = t - a / b * y;
return g;
}
int f(int t, int x, int y) {
int r = x + b * t, s = y - a * t;
int ans = INF;
if (r >= 0 && s >= 0)
ans = min(ans, 2 * (r + s));
else
ans = min(ans, 2 * (abs(r) + abs(s)) - 1);
return ans;
}
void solve() {
int k;
cin >> a >> b >> k;
if (k % __gcd(a, b)) {
cout << -1 << "\n";
} else {
// ax+by=k
int x, y;
int g = exgcd(a, b, x, y);
int res = INF;
a /= g, b /= g, k /= g;
x *= k, y *= k;
int cnt = -x / b;
for (int i = cnt - 1; i <= cnt + 1; i++) res = min(res, f(i, x, y));
cnt = y / a;
for (int i = cnt - 1; i <= cnt + 1; i++) res = min(res, f(i, x, y));
cout << res << "\n";
}
}
signed main() {
IOS;
int t = 1;
cin >> t;
for (int i = 1; i <= t; i++) {
solve();
}
}