2023牛客多校第一场补题报告D J K M

2023牛客多校第一场补题报告D J K M

D-Chocolate_“范式杯”2023牛客暑期多校训练营1 (nowcoder.com)

思路

对于先手只要不是一次就会取完的1 * 1矩阵,总有获胜办法

代码

#include<bits/stdc++.h>
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";
	}
}

J-Roulette_“范式杯”2023牛客暑期多校训练营1 (nowcoder.com)

思路

我们注意到,其实每次获胜只会让总额增长1,所以就是要获胜m场,两场之间输的次数不能超过目前本金的二进制最高位1的位数,然后相乘即可。

代码

#include <bits/stdc++.h>
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";
}

K-Subdivision_“范式杯”2023牛客暑期多校训练营1 (nowcoder.com)

思路

我们可以bfs先搜一下到最短路径之前可以走多少步,然后我们贪心的思考,对于影响后续结点只有1的点进行增点,否则不增点。

代码

#include <bits/stdc++.h>
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<int> ve[N];
int dis[N];
vector<pair<int,int>> 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<int> 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;
}

M-Water_“范式杯”2023牛客暑期多校训练营1 (nowcoder.com)

思路

一眼exgcd,赛时卡住的问题在于怎么样取最小,其实列出方程就是ax+by=k,其中如果x,y是正数,则需要花费乘以2的操作数(倒入再倒出),负数可以减一(最后一次保留在杯子中不倒出),然后求通解即可。

代码

#include <bits/stdc++.h>
#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<int, int> 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();
  }
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值