牛客 小白107 20250118

牛客 小白107 20250118

牛客小白月赛107_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ

A:

题目大意:给定一个 \(n\) ,根据不同的范围输出不同的结果

#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,a,b,c;
int cnt=0;
cin>>n>>a>>b>>c;
while (n>a){
n-=a;
cnt++;
}
while (n>b){
n-=b;
cnt++;
}
while (n>c){
n-=c;
cnt++;
}
cout<<cnt;
}

简单签到

B:

题目大意:给定一个序列,每次循环进行两种操作,求使数列元素相同的最少操作数

  1. 选择任意多的数加 \(1\)
  2. 选择任意少的数减 \(1\)
#include<bits/stdc++.h>
using namespace std;
int n, a;
int minm=1e9, maxm=-1e9;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a;
if (a[i] < minm) minm = a;
if (a[i] > maxm) maxm = a;
}
long long avg = (minm + maxm + 1) >> 1;
cout <<abs(maxm-avg)+abs(minm-avg)<< ' ' << avg;
return 0;
}

最终的操作数只有两种情况:

  • 操作1做 \(n+1\) 次,操作2做 \(n\)
  • 操作1和操作2都做 \(n\)

所以输出序列的最大值减去序列的最小数向上取整即可(操作1可多做一次)

C:

题目大意:

有一个 \(n\)\(m\) 列的花园,每个坐标上没有植物,现在对这个花园做 \(k\) 次如下操作

  1. 选择第 \(i\) 行,在没有植物的地方种下 \(x\) 植物
  2. 选择第 \(a\)\(b\) 列,如果坐标上有植物就铲掉

操作数列由以下参数生成:

def rnd():
p=(1<<32)
ret=seed
seed=(seed xor ((seed<<13) mod p)) mod p
seed=(seed xor ((seed>>17) mod p)) mod p
seed=(seed xor ((seed<<5) mod p)) mod p
return ret
for t=1 to k:
op[t]=(rnd() mod 2) + 1
if op[t]==1:
i[t]=(rnd() mod m) + 1
x[t]=(rnd() mod (n*m)) + 1
if op[t]==2:
a[t]=(rnd() mod n) + 1
b[t]=(rnd() mod m) + 1

其中 ·rnd 给出 cpp 的代码如下:

unsigned seed;
unsigned rnd(){
unsigned ret=seed;
seed^=seed<<13;
seed^=seed>>17;
seed^=seed<<5;
return ret;
}

其中的 \(seed\) 由输入给定,\(op[t]\) 表示第 \(t\) 次操作编号

结果只需要输出以下计算的结果

\[\bigoplus_{i=1}^n\bigoplus_{j=1}^m p_{i,j}\times((i-1)\times m+j) \]

#include<bits/stdc++.h>
using namespace std;
const int N = 5000010;
unsigned int seed;
unsigned int rnd() {
unsigned ret = seed;
seed ^= seed << 13;
seed ^= seed >> 17;
seed ^= seed << 5;
return ret;
}
long long n, m, k;
long long op, i, x, a, b;
long long arr[20010][210];
int main()
{
cin >> n >> m >> k >> seed;
vector<int> st[210];
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++)
st[i].push_back(j);
for (int t = 1; t <= k; t++) {
op = (rnd() % 2) + 1;
if (op == 1) {
i = (rnd() % m) + 1;
x = (rnd() % (n * m)) + 1;
if (st[i].empty()) continue;
for (auto iter:st[i])
arr[iter][i]=x;
st[i].clear();
}
if (op == 2) {
a = (rnd() % n) + 1;
b = (rnd() % m) + 1;
arr[a][b]=0;
st[b].push_back(a);
}
}
long long ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
ans ^= arr[i][j] * ((i - 1) * m + j);
}
}
cout << ans;
return 0;
}

数据量大,暴力要超时

观察操作方式可以知道,所以的操作都是对于空地进行修改

所以可以构造一个状态数组,来记录每个位置地块的状态

if (st[i].empty()) continue;//如果当前列全是空地,那就不种
for (auto iter:st[i])//记录的列空地
arr[iter][i]=x;//空地种上x
st[i].clear();//这一列清空
arr[a][b]=0;//铲除对应位置上的植物
st[b].push_back(a);//在状态数组里面加入这块新空地

D:

题目大意:给出一个字符串,合并一些长 \(k\) 的字符串得到 $t $,\(t_{[i,j]}\) 表示 \(t\)\(i\)\(j\) 的子串,记 \(s\) 含有的长为 \(k\) 的子串按照左端点从左到右的顺序为 \(p_1,p_2,\dots,p_{n-k+1}\)。存在一个非负整数序列 \(a\) 满足:

  • \(a_1=0\)
  • \(\forall i\in [1,n-k],0\le a_{i+1}-a_i\le 1\)
  • \(\forall i\in [1,n-k+1],p_i=t_{[i-a_i,i+k-1-a_i]}\)

设对于 \(k\) 生成的 \(t\) 最短长度为 \(l_k\) ,求出 \(\bigoplus_{i=1}^ni\times l_i\)

#include<bits/stdc++.h>
using namespace std;
int l[5000010];
int main()
{
string str;
int n;
cin>>n>>str;
int cnt=0;
for (int i=1;i<n;i++){
if (str[i]==str[i-1]){
cnt++;
l[cnt]--;
}else
cnt=0;
}
for (int i=n;i>1;i--)
l[i-1]+=l[i];
long long ans=0;
for (int k=1;k<=n;k++)
ans^=(long long)k*(l[k]+n);
cout<<ans<<endl;
return 0;
}

题面很臭,弯弯绕绕,本质是问一个序列,将长度大于 \(l_k\) 的部分压缩到 \(l_k\) ,问最后的序列长度 (\(t\))

aabbbaaa 为例,当 \(k=2\) 时有:p1=aa,p2=ab,p3=bb,p4=bb,p5=ba,p6=aa,p7=aa

因为需要满足 \(\forall i\in [1,n-k+1],p_i=t_{[i-a_i,i+k-1-a_i]}\),所以\(p_3=p_4\),对应的 \(a_4=a_5=1,a_7=2\)

此时有 \(p_3=p_4=t_{[3,4]}\)

对读入的字符串进行预处理,计算每个有连续字符的子串对整体的贡献 cnt++; l[cnt]--;

然后从第 \(n\) 项往回递推,计算每个 \(k\) 下对应的应该减去的长度,最后套公式计算即可

posted @ 2025-01-20 19:18  才瓯  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示