2023牛客多校第四场补题报告A F H J L

2023牛客多校第四场补题报告A F H J L

A-Bobo String Construction_2023牛客暑期多校训练营4 (nowcoder.com)

思路

尝试全1或者全0,其中必定有一个可以。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
void solve();
signed main(){
	cin.sync_with_stdio(0);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while(T--){
		solve();
	}
	return 0;
}

// s[]是长文本,p[]是模式串,n是s的长度,m是p的长度

int kmp(string s,string p){
	int ret = 0;
	int ne[3030];
	memset(ne,0,sizeof ne);
	int n = s.size();
	int m = p.size();
	s = " " + s;
	p = " " + p;
	for (int i = 2, j = 0; i <= m; i ++ )
	{
		while (j && p[i] != p[j + 1]) j = ne[j];
		if (p[i] == p[j + 1]) j ++ ;
		ne[i] = j;
	}
	
// 匹配
	for (int i = 1, j = 0; i <= n; i ++ )
	{
		while (j && s[i] != p[j + 1]) j = ne[j];
		if (s[i] == p[j + 1]) j ++ ;
		if (j == m)
		{
			j = ne[j];
			// 匹配成功后的逻辑
			ret ++;
		}
	}
	return ret;
}


void solve(){
	int n;
	cin >> n;
	string t;
	cin >> t;
	string s = "";
	for(int i = 1;i <= n;i ++) {
		s += "1";
	}
	if(kmp(t + s + t,t) == 2) {
		cout << s << endl;
		return;
	}
	s = "";
	for(int i = 1;i <= n;i ++) {
		s += "0";
	}
	if(kmp(t + s + t,t) == 2) {
		cout << s << endl;
		return;
	}
	cout << -1 << endl;
}

F-Election of the King_2023牛客暑期多校训练营4 (nowcoder.com)

思路

直接找到基准线,每次淘汰必定是两端的,不断二分即可。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve();
signed main(){
	//cin.sync_with_stdio(0);
	//cin.tie(0);
	int T = 1;
	//cin >> T;
	while(T--){
		solve();
	}
	return 0;
}
void solve(){
	int n;
	cin >> n;
	vector<pair<int,int>> a;
	for(int i = 0;i < n;i++){
		int ai;
		cin >> ai;
		a.push_back({ai, i + 1});
	}
	sort(a.begin(), a.end());
	int l = 0, r = n - 1;
	while(l < r){
		int m = a[l].first + a[r].first;
		if(m % 2 == 1){
			m = m / 2 + 1;
			int vl = r - (lower_bound(a.begin() + l, a.begin() + r + 1, make_pair(m, 0ll)) - (a.begin())) + 1;
			int vr = r - l + 1 - vl;
			if(vl > vr){
				l++;
			}
			else{
				r--;
			}
		}
		else{
			m = m / 2;
			int vl = r - (lower_bound(a.begin() + l, a.begin() + r + 1, make_pair(m + 1, 0ll)) - (a.begin())) + 1;
			int vr = r - l + 1 - vl;
			if(vl > vr){
				l++;
			}
			else{
				r--;
			}
		}
	}
	cout << a[l].second << "\n";
}

H-Merge the squares!_2023牛客暑期多校训练营4 (nowcoder.com)

思路

不断切分,尝试,递归操作一定可以证明出来有矩形最后一定可以有24个以内的正方形构成。不会证明其正确性和时间复杂度,很玄学。

代码

#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;
int a[N];

int check(int x, int y) {
  if (x == y) {
    return 1;
  }

  if (y > x)
    return 1 + check(x, y - x);
  else
    return 1 + check(x - y, y);
}
void f(int x, int y, int s);
void f(int x, int y, int s1, int s2) {
  if (s1 == s2) {
    f(x, y, s1);
    return;
  }
  if (s1 > s2) {
    f(x, y, s1 - s2, s2);
    f(x + s1 - s2, y, s2);
  } else {
    f(x, y, s1, s2 - s1);
    f(x, y + s2 - s1, s1);
  }
}
vector<array<int, 3>> res;
void f(int x, int y, int s) {
  if (s == 1) {
    return;
  } else if (s > 7) {
    for (int i = 1; i < s; i++) {
      if (2 + 2 * check(i, s - i) <= 50) {
        // cout << check(i, s - i) << "\n";
        f(x, y, i);
        f(x + i, y, s - i, i);
        f(x + i, y + i, s - i);
        f(x, y + i, i, s - i);
        break;
      }
    }
  }

  res.push_back({x, y, s});
}

void solve() {
  cin >> n;
  f(1, 1, n);
  cout << res.size() << "\n";
  for (auto [i, j, k] : res) {
    cout << i << " " << j << " " << k << "\n";
  }
}

signed main() {
  IOS;
  int t = 1;
  //cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

J-Qu’est-ce Que C’est?_2023牛客暑期多校训练营4 (nowcoder.com)

思路

其实看到很容易想到dp,但是状态转移的细节比较多,还需要差分优化,否则会t掉。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve();
signed main(){
	//cin.sync_with_stdio(0);
	//cin.tie(0);
	int T = 1;
	//cin >> T;
	while(T--){
		solve();
	}
	return 0;
}
#define N 5050
int dp[N][2 * N];
#define mod 998244353
void solve(){
	int n, m;
	cin >> n >> m;
	for(int i = -m;i <= m;i++){
		dp[1][i + 5050] = 1;
	}
	for(int i = 2;i <= n;i++){
		for(int j = -m;j <= m;j++){
			if(j < 0){
				(dp[i][0 + 5050] += dp[i - 1][j + 5050]) %= mod;
				dp[i][j + m + 1 + 5050] -= dp[i - 1][j + 5050];
				dp[i][j + m + 1 + 5050] = dp[i][j + m + 1 + 5050] % mod + mod;
				dp[i][j + m + 1 + 5050] %= mod;
			}
			else{
				(dp[i][-j + 5050] += dp[i - 1][j + 5050]) %= mod;
				dp[i][m + 1 + 5050] -= dp[i - 1][j + 5050];
				dp[i][m + 1 + 5050] = dp[i][m + 1 + 5050] % mod + mod;
				dp[i][m + 1 + 5050] %= mod;
			}
		}
		for(int j = -m;j <= m;j++){
			dp[i][j + 5050] += dp[i][j - 1 + 5050];
			dp[i][j + 5050] %= mod;
		}
	}
	int ans = 0;
	for(int i = -m;i <= m;i++){
		ans += dp[n][i + 5050];
		ans %= mod;
	}
	cout << ans << "\n";
}

L-We are the Lights_2023牛客暑期多校训练营4 (nowcoder.com)

思路

就是倒着思考,直接二分计算每个位置会被开关多少次。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve();
signed main(){
	//cin.sync_with_stdio(0);
	//cin.tie(0);
	int T = 1;
	//cin >> T;
	while(T--){
		solve();
	}
	return 0;
}
#define N 1000010
int r[N], c[N];
void getq(int id){
	string s;
	cin >> s;
	int x;
	cin >> x;
	string t;
	cin >> t;
	if(t == "off")id = -id;
	if(s == "row"){
		r[x] = id;
	}
	else{
		c[x] = id;
	}
}
void solve(){
	int n, m, q;
	cin >> n >> m >> q;
	for(int i = 1;i <= q;i++){
		getq(i);
	}
	vector<int> rg, rk, cg, ck;
	for(int i = 1;i <= n;i++){
		if(r[i] > 0){
			rk.push_back(r[i]);
		}
		if(r[i] < 0){
			rg.push_back(-r[i]);
		}
	}
	for(int i = 1;i <= m;i++){
		if(c[i] > 0){
			ck.push_back(c[i]);
		}
		if(c[i] < 0){
			cg.push_back(-c[i]);
		}
	}
	sort(rg.begin(), rg.end());
	sort(rk.begin(), rk.end());
	sort(cg.begin(), cg.end());
	sort(ck.begin(), ck.end());
	int ans = 0;
	for(int i = 1;i <= n;i++){
		if(r[i] > 0){
			ans += m - (lower_bound(ck.begin(), ck.end(), r[i]) - ck.begin()) - (cg.end() - lower_bound(cg.begin(), cg.end(), r[i]));
		}
	}
	for(int i = 1;i <= m;i++){
		if(c[i] > 0){
			ans += n - (lower_bound(rk.begin(), rk.end(), c[i]) - rk.begin()) - (rg.end() - lower_bound(rg.begin(), rg.end(), c[i]));
		}
	}
	cout << ans << "\n";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值