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";
}