牛客周赛 Round 68(A~F)
比赛链接:https://ac.nowcoder.com/acm/contest/95928#question
这次D题小细节搞了好久,越界了好几次,没想到赛后做E,发现还更简单
A.三途川的摆渡人(二)
题面:
小红这天来到了三途川,发现这里有一个摆渡人,名字叫小町。
小町的职责是将一些灵魂运送到冥界。但小町非常喜欢偷懒,她经常在上班的时候摸鱼,导致很多灵魂不能成功送达,因此在彼岸开出了许多彼岸花。
小红准备统计彼岸花的数量,她把排队等待摆渡的灵魂用一个01串来表示,'0'代表因小町摸鱼未能上船的灵魂,'1'代表成功到达冥界的灵魂。每个未上船的灵魂都将化为一朵彼岸花,请你帮小红计算彼岸花的数量。
输入:
第一行输入一个正整数n,代表灵魂的数量。
第二行输入一个长度为n的01串,代表每个灵魂是否成功被小町送往冥界。
输出:
一个整数,代表彼岸花的数量。
样例:
4
0100
——————
3
思路:彼岸花数量就是字符串中0数量,直接遍历
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll n;
cin>>n;
string f;
cin>>f;
ll ans=0;
for(ll i=0;i<f.size();i++)
{
if(f[i]=='0')ans++;
}
cout<<ans<<endl;
}
B.魔法之森的蘑菇(二)
题面:
小红在魔法之森迷路了,森林中有一些致幻的毒蘑菇。森林用一个𝑛行𝑚列的矩阵表示。
小红准备采集一个矩形区域里的资源,但小红非常讨厌蘑菇,因此她希望这个矩形内没有任何蘑菇。
小红希望你帮她计算出一个面积最大的、且不包含蘑菇的矩形区域。
输入:
第一行输入两个正整数𝑛,𝑚代表矩阵的行数和列数。
接下来的𝑛行,每行输入一个长度为𝑚的字符串,用来表示森林地图。
保证所有的字符仅有'.'和''这两种,其中'.'代表道路,''代表蘑菇
输出:
四个整数
样例:
3 3
——————
1 1 3 1
思路:二维前缀和+暴力枚举,首先用二维前缀处理好所*的个数,然后暴力&n^4&枚举左上角和右下角,随后每次减一下检测一下是否全为0即可,然后再比较下当前面积和记录的最大面积。如果能更新就更新,然后更新2个点的坐标
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll pre[50][50];
int main()
{
fio();
ll n,m;
cin>>n>>m;
string f[50];
for(ll i=1;i<=n;i++)cin>>f[i],f[i]='0'+f[i];
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=m;j++)
{
pre[i][j]=pre[i][j-1]+pre[i-1][j]-pre[i-1][j-1]+(f[i][j]=='*');
}
}
ll ans=0;
ll l,r,l1,r1;
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=m;j++)
{
for(ll k=i;k<=n;k++)
{
for(ll c=j;c<=m;c++)
{
// if(k==3&&c==3&&i==3&&j==1)
// {
// cout<<pre[k][c]-pre[k][j-1]-pre[i-1][c]+pre[i-1][j-1]<<endl;
// }
if(pre[k][c]-pre[k][j-1]-pre[i-1][c]+pre[i-1][j-1]==0)
{
if(ans<(c-j+1)*(k-i+1))
{
ans=(c-j+1)*(k-i+1);
l=i,r=j,
l1=k,r1=c;
}
}
}
}
}
}
cout<<l<<" "<<r<<" "<<l1<<" "<<r1<<endl;
}
C.迷途之家的大贤者(二)
题面:
小红在穿越后不久,就被大贤者小紫发现了,于是小紫友好地请小红来迷途之家做客。
她们准备玩一个游戏,两人分别拿到了一个长度为
对于每次操作,两人可以同时删除自己数组中任意一个元素。她们希望两人通过若干次删除操作,使得操作后的两个数组中所有元素均互不相同。例如
你能帮小红求出操作的最小次数吗?
输入:
第一行输入一个正整数
第二行输入
第三行输入
输出:
一个整数,代表操作的最小次数。
样例:
4
1 2 1 3
2 4 3 5
————
2
思路:首先思考下,发现删除自己重复的数是最优先的,然后再删除和别人重复的是其次的,所以通过这种方法可以讨论,先分别记录两个数组的删自己重复数的次数:cnt,cnt1
如果cnt==cnt1
则剩下的数一定是重复的且其值为1,所以答案为(重复的数的种类+1)/2+cnt
如果cnt>cnt1
首先则剩下的两者重复的数,后者可以先删除cnt-cnt1个,随后答案为(重复的数的种类-(cnt-cnt1)+1)/2+cnt
否则反之
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll a[500000];
ll b[500000];
int main()
{
fio();
ll n;
cin>>n;
map<ll,ll>q1,q2;
set<ll>f;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
q1[a[i]]++;
f.insert(a[i]);
}
for(ll i=1;i<=n;i++)cin>>b[i],q2[b[i]]++,f.insert(b[i]);
ll ans=0;
ll cnt=0;
ll cnt1=0;
for(auto j:f)
{
if(q1[j]>0)
cnt+=q1[j]-1;
if(q2[j]>0)
cnt1+=q2[j]-1;
}
//ll ans=0;
if(cnt==cnt1)
{
ll cs=0;
for(auto j:f)
{
if(q1[j])q1[j]=1;
if(q2[j])q2[j]=1;
if(q1[j]&&q2[j])cs++;
}
cout<<(cs+1)/2+cnt<<endl;
}
else if(cnt>cnt1)
{
ll co=cnt-cnt1;
ll cs=0;
for(auto j:f)
{
if(q1[j])q1[j]=1;
if(q2[j])q2[j]=1;
if(q1[j]&&q2[j])
{
if(co)
{
co--;
continue;
}
else
{
cs++;
}
}
}
cout<<(cs+1)/2+cnt<<endl;
}
else
{
swap(cnt,cnt1);
ll co=cnt-cnt1;
ll cs=0;
for(auto j:f)
{
if(q1[j])q1[j]=1;
if(q2[j])q2[j]=1;
if(q1[j]&&q2[j])
{
if(co)
{
co--;
continue;
}
else
{
cs++;
}
}
}
cout<<(cs+1)/2+cnt<<endl;
}
}
D.红魔馆的馆主(二)
题面:
小红来到了红魔馆。众所周知,红魔馆的馆主是一只495岁的吸血鬼,所以她非常喜欢495这个数。
现在小红拿到了一个数组,她认为该数组的“美丽度”为:选两个元素
小红可以进行最多1次操作:选择一个元素,使其加1。请你帮小红求出最多1次操作后,数组的最大美丽度。
输入:
第一行输入一个正整数
第二行输入
输出:
一个整数,代表最多一次操作后,数组的最大美丽度。
样例:
4
1 9 55 494
————
4
思路:从495的因数出发,显然一个数存有495因数,那么他乘以其他带有495因数的数结果%495==0,就等价于他们相乘是为495的倍数。
所以先用个数组存495的所有因数可能,然从大到小排序,去重。总共12种可能
然后对于每个数标记它属于哪个可能,即第一次被模除的数的存储下标
用前缀数组和后缀数组,存储和所有状态并传递
首先对于不操作的答案,直接用后缀数组+判断它和其他11种组合是否构成495倍数可以计算出
然后暴力枚举,每个数加+1的情况,首先用前后缀数组把它所有可能都减掉,然后加1,再判断它属于哪种可能
,再次用前后缀数组把他所用可能都加起来,最后取个max
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll a[500000];
ll pre[14][500000];
ll sub[14][500000];
ll d[500000];
int main()
{
fio();
ll n;
cin>>n;
memset(d,0,sizeof d);
ll b[60]={0,495,165,99,45,55,33,15,9,11,5,3,1};
for(ll i=1;i<=n;i++)
{
cin>>a[i];
ll u=a[i];
for(ll k=1;k<=12;k++)
{
pre[k][i]=pre[k][i-1];
}
for(ll j=1;j<=12;j++)
{
if(a[i]%b[j]==0)
{
d[i]=j;
pre[j][i]++;
break;
}
}
}
for(ll i=n;i>=1;i--)
{
for(ll k=1;k<=12;k++)
{
sub[k][i]=sub[k][i+1];
}
for(ll j=1;j<=12;j++)
{
if(a[i]%b[j]==0)
{
sub[j][i]++;
break;
}
}
}
ll ans=0;
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=12;j++)
{
if((b[j]*b[d[i]])%495==0)
{
ans+=sub[j][i+1];
}
}
}
ll u=ans;
//cout<<u<<endl;
ll cnt;
for(ll i=1;i<=n;i++)
{
cnt=u;
for(ll j=1;j<=12;j++)
{
if((b[j]*b[d[i]])%495==0)
{
// if(i==1)
// cout<<j<<endl;
cnt-=pre[j][i-1]+sub[j][i+1];
}
}
a[i]++;
ll wz=0;
for(ll j=1;j<=12;j++)
{
if(a[i]%b[j]==0)
{
wz=j;
break;
}
}
for(ll j=1;j<=12;j++)
{
if((b[j]*b[wz])%495==0)
{
cnt+=pre[j][i-1]+sub[j][i+1];
}
}
ans=max(ans,cnt);
}
cout<<ans<<endl;
}
E.博丽神社的巫女(二)
题面:
小红来到了博丽神社,发现博丽神社门口有一个赛钱箱。
这时神社里走出了一个巫女,对小红说:给你一个数组,你可以对任意元素进行任意次“该元素除以2向下取整”的操作,只要你能让这个数组所有元素之和等于100000,你就能拿走赛钱箱里所有的钱,否则你就必须往赛钱箱投十万元,你想和我玩这个游戏吗?
小红很想赚取赛钱箱里的金币,请你帮帮小红。
输入:
第一行输入一个正整数
第二行输入
保证所有元素之和
输出:
如果小红必然输掉游戏,请输出-1。
否则输出
样例:
2
50000 100000
————
0 1
思路:分组背包变形+set转移数组。首先加和达不到100000直接判-1。
然后考虑如何变形,把原本凑100000,变成是否能减sum-100000,随后这个差值用分组背包变形就好,除了0其他都得复制为一个极大值
首先预处理一个数的所有可能差值与操作次数,vector记住,随后就是分组背包跑一遍,记得set开pair记录操作次数和对谁操作
最后判断dp[sum-100000]是否仍为极大值,如果是,输出-1,否则输出答案
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll a[500];
vector<pair<ll,ll>>g[250];
set<pair<ll,ll>>q[200001];
ll dp[1500000];
ll b[250000];
int main()
{
fio();
ll n;
cin>>n;
ll sum=0;
for(ll i=1;i<=n;i++)cin>>a[i],sum+=a[i];
for(ll i=1;i<=n;i++)
{
ll cs=0;
ll u=a[i];
while(u)
{
u/=2;
cs++;
g[i].push_back({cs,a[i]-u});
}
}
if(sum<100000)
{
cout<<-1<<endl;
}
else
{
sum-=100000;
for(ll i=1;i<=sum;i++)
{
dp[i]=9999999999;
}
for(ll i=1;i<=n;i++)
{
for(ll j=sum;j>=1;j--)
{
for(auto k:g[i])
{
ll u=k.first;
ll f=k.second;
if(j>=f)
{
if(dp[j]>dp[j-f]+1)
{
dp[j]=dp[j-f]+1;
q[j].clear();
q[j].insert({u,i});
q[j].insert(q[j-f].begin(),q[j-f].end());
}
}
}
}
}
if(dp[sum]==9999999999)cout<<-1<<endl;
else
{
for(auto j:q[sum])
{
b[j.second]=j.first;
}
for(ll i=1;i<=n;i++)cout<<b[i]<<" ";
cout<<endl;
}
}
}
F.雾之湖的冰精(三)
题面:
雾之湖里有一只聪慧的冰精,她会进行9以内的加法运算,然而当计算的结果超过9了她的脑子就会陷入红温。
小红拿到了一棵树,每个节点的权值为
我们认为,一个合法的路径应至少包含2个节点。u->v或者v->u我们视为同一条路径。
输入:
第一行输入一个正整数
第二行输入
接下来
输出:
输出一个整数,代表合法的路径数量。
样例:
3
3 4 5
1 2
2 3
2
思路:看了题解,这道题dp确实好解,一个节点的答案首先肯定与周边节点的状态有关,反正状态才0到9,直接暴力转移。
在一条链上,直接dp[x][i]+=dp[j][i-a[x]],暴力枚举转移(j为儿子,x为现在节点,i为枚举量,范围[a[x],9]),这个在最后结算。对于多条链的,首先x节点肯定参与了,然后用个新数组去记录最近的儿子的值,然后每有一个儿子就进行一次乘法运算(二重循环)就可以了,乘法运算完了,直接结算,结算完一次后还得再次加上此时儿子的贡献。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<stdio.h>
#include<cstdio>
#include<vector>
// #include<bits/stdc++.h>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll maxn = 1e5+5;
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll ksm(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1)
ans=ans%mod*(x%mod)%mod;
x=x%mod*(x%mod)%mod;
y>>=1;
}
return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
if(y==0)
return x;
else
return gcd(y,x%y);
}
ll a[100005];
vector<ll>g[100005];
ll dp[100005][12];
ll ans=0;
void dfs(ll x,ll fa)
{
ll s[10];
for(ll i=0;i<=9;i++)
s[i]=0;
for(auto j:g[x])
{
if(j==fa)continue;
dfs(j,x);
for(ll i=a[x];i<=9;i++)
{
dp[x][i]+=dp[j][i-a[x]];//单项状态转移
}
for(ll i=0;i<=9;i++)
{
for(ll u=0;u<=9-i-a[x];u++)
ans+=dp[j][i]*s[u];
}
for(ll i=0;i<=9;i++)
{
s[i]+=dp[j][i];
}
}
for(ll i=0;i<=9;i++)ans+=dp[x][i];
dp[x][a[x]]++;
}
int main()
{
fio();
ll n;
cin>>n;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
}
for(ll i=1;i<=n-1;i++)
{
ll l,r;
cin>>l>>r;
g[l].push_back(r);
g[r].push_back(l);
}
for(ll i=1;i<=n;i++)
{
if(g[i].size()==1)
{
dfs(i,-1);
break;
}
}
cout<<ans<<endl;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具