题解(自记录) | 牛客寒假集训营20250121第一场比赛

A.茕茕孑立之影

题目:https://ac.nowcoder.com/acm/contest/95323/A

#include<bits/stdc++.h>

using namespace std;

int main(){

int n,t,x;

cin >> n;

while(n--){

cin >> t;

int ans=1e9+7;

for(int i=0;i<t;i++){

cin >> x;

if(x==1)ans=-1;

}

cout << ans <<endl;

}

}

题解思路:题目要求为一个数不为该数组任何数倍数,也不允许该数组任何数为该数倍数。当该数组存在1时,必不可能满足即必然输出-1;当数组不存在1时,一个极大的素数必定满足条件,则输出任意一个极大的素数即可。

B.一气贯通之刃

题目:https://ac.nowcoder.com/acm/contest/95323/B

#include<bits/stdc++.h>

using namespace std;

int main(){

int n,s1,s2,f=0;

cin >> n;

vector<int>a(n+1);

for(int i=1;i<n;i++){

cin >> s1 >> s2;

a[s1]++;a[s2]++;

}

vector<int>b;

for(int i=1;i<=n;i++){

if(a[i]==1)b.push_back(i);

else if(a[i]>2)f=1;

}

if(f==1)cout << -1;

else cout << b[0] << " " << b[1];

}

题解思路:题目要求寻找一条简单路径通过所有节点,即一条链,则选择获取每个数字出现的频率,如果为一条链则存在首尾两个数出现频率为1,其余数皆为2,如果存在出现频率大于2的数则无法通过所有节点

C.兢兢业业之移

题目:https://ac.nowcoder.com/acm/contest/95323/C

D.双生双宿之决

题目:https://ac.nowcoder.com/acm/contest/95323/D

#include<bits/stdc++.h>

using namespace std;

int main(){

int n,t;

cin >> t;

while(t--){

cin >> n;

vector <int> a(n);

for(int i=0;i<n;i++){

cin >> a[i];}

if(n%2!=0){cout<<"No"<<endl;continue;}

sort(a.begin(),a.end());

int j=1;

while(a[0]==a[j]){

j++;

}

int w=n-2;

while(a[n-1]==a[w]){

w--;

}

w++;

if(j==w&&j==n/2)cout << "Yes"<<endl;

else cout << "No"<<endl;

}

}

题解思路:题目要求数组中仅有两个出现次数相同的数字,那就顺题意分别从前往后和从后往前清点数字出现的次数,然后计算两个数字是否为数组的一半即可。

E. 双生双宿之错

题目:https://ac.nowcoder.com/acm/contest/95323/E

#include<bits/stdc++.h>

#define ll long long

using namespace std;

int main() {

int T;

cin >> T;

while(T--){

ll n,ans=0,l,r,l1,r1,ans1=0;

cin >> n;

vector<ll>a(n+1);a[0]=-2e9;

for(int i=1;i<=n;i++){

cin >> a[i];

}

sort(a.begin(),a.end());

int half=n/2;

if(half%2==0){

l=(a[(n/2)/2]+a[(n/2)/2+1])/2;

r=(a[((n/2)+n)/2]+a[((n/2)+n)/2+1])/2;}

else{

l=(a[(half+1)/2]);

r=(a[(half+(half+1)/2)]);

}

if(l!=r){

for(int i=1;i<=n/2;i++)ans+=abs(a[i]-l);

for(int i=n/2+1;i<=n;i++)ans+=abs(a[i]-r);

}

else{

l1=l-1;r1=r;

for(int i=1;i<=n/2;i++)ans1+=abs(a[i]-l1);

for(int i=n/2+1;i<=n;i++)ans1+=abs(a[i]-r1);

r=r1+1;

for(int i=1;i<=n/2;i++)ans+=abs(a[i]-l);

for(int i=n/2+1;i<=n;i++)ans+=abs(a[i]-r);

ans=min(ans,ans1);

}

cout << ans <<endl;

}

}

题解思路:由题意可知通过任意次-1,+1的操作将数组变为双生数组,将数组分为左右数组其最小操作次数则,将所有数变为其中位数。当左右数组中位数相等时,枚举左边为中位数-1和右边为中位数+1,取其最小

F.双生双宿之探

题目:https://ac.nowcoder.com/acm/contest/95323/F

G.井然有序之衡

题目:https://ac.nowcoder.com/acm/contest/95323/G

#include<bits/stdc++.h>

#define ll long long

using namespace std;

int main(){

ll n,sum=0,num=0;

cin >> n;

vector<ll>a(n+1);

for(int i=1;i<=n;i++){

cin >> a[i];

}

a[0]=-2e9;

sort(a.begin(),a.end());

for(int i=1;i<=n;i++){

sum+=a[i]-i;

if(i>a[i])num+=i-a[i];

}

if(sum)num=-1;

cout << num << endl;

}

题解思路:题目要求通过+1,-1将数组变为排列,即变为(1-n)的形式,那先将无序数组进行排列,由于最终数列内的值之和不变,所以通过计算数组的和可以知道是否能变为排列,将数组和目标值相减,sum为相差之和,num仅计算+1部分,可算得操作次数

H.井然有序之窗

题目:https://ac.nowcoder.com/acm/contest/95323/H

#include<bits/stdc++.h>

#define ll long long

using namespace std;

int main() {

int n,num=0;

cin >> n;

deque<array<int,3>>a(n);

set<array<int,3>>st;

for(auto& [l,r,i] : a){

cin >> l >> r;

i=++num;

}

sort(a.begin(),a.end());

vector<ll>ans(n+1);

for(int i=1;i<=n;i++){

while(a.size() && a[0][0] <= i){

auto[l,r,i]=a[0];

st.insert({r,l,i});

a.pop_front();

}

if(!st.size()){

cout << -1 <<endl;

return 0;

}

auto[r,l,j]=*st.begin();

st.erase(st.begin());

if(r < i){

cout << -1 << endl;

return 0;

}

ans[j]=i;

}

for(int i=1;i<=n;i++){

cout << ans[i]<<" ";

}

}

题解思路:题目给出数组中每个数字的区间,这段代码先设定一个set和一个双端队列,先对deque<int>a进行l,r从小到大排序,将满足左端点条件的点加入set中,并更换l,r位置使得右端点更小的值更早被使用掉,i作为记录位置的值将ans按位置输出答案;

I.井然有序之桠

题目:https://ac.nowcoder.com/acm/contest/95323/I

J.硝基甲苯之袭

题目:https://ac.nowcoder.com/acm/contest/95323/J

#include<bits/stdc++.h>

#define ll long long

using namespace std;

int main() {

int n;

cin >> n;

vector<ll>a(n+1);map<ll,ll>s;

for(int i=1;i<=n;i++){

cin >> a[i];

s[a[i]]++;

}

ll num=0;

for(int i=1;i<=n;i++){

unordered_set<ll>c;

for(int j=1;j*j<=a[i];j++){

if(a[i]%j==0){

int x1=j,x2=a[i]/j;

if(__gcd(x1^a[i],a[i])==x1 && !c.count(x1^a[i])){

num+=s[x1^a[i]];

c.insert(x1^a[i]);

}

if(__gcd(x2^a[i],a[i])==x2 && !c.count(x2^a[i])){

num+=s[x2^a[i]];

c.insert(x2^a[i]);

}

}

}

}

cout << num/2 << endl;

}

题解思路:题目要求数组中两个数满足x^y=gcd(x,y)到底有多少组,根据异或性质,y=gcd(x,y)^x,那么从x的因子中寻找gcd并且推出y,再将值带回上式,若满足则查找数组中有几个满足条件的数字并加入num并输出.

M.数值膨胀之美

题目:https://ac.nowcoder.com/acm/contest/95323/M

#include<bits/stdc++.h>

#define ll long long

using namespace std;

int main() {

int n;

cin >> n;

pair<int,int>a[100001];

vector<ll>b;

for(int i=0;i<n;i++){

cin >> a[i].first,b.push_back(a[i].first);

a[i].second=i;

}

a[n].first=2e9;

sort(a,a+n);

ll ma=max(a[0].first*2,a[n-1].first),l=a[0].second,r=a[0].second;

ll ans=ma-min(a[0].first*2,a[1].first);

b[l]=b[l]*2;

for(int i=1;i<n;i++){

while(a[i].second<l){

l--;

ma=max(ma,b[l]*2);

}

while(a[i].second>r){

r++;

ma=max(ma,b[r]*2);

}

ans=min(ans,ma-min(a[i+1].first,a[0].first*2));

}

cout << ans;

}

题解思路:题目要求从数组中取一个非零区间进行全部乘2,那就从最小值开始,一一遍历次小值并将其乘2,并在最小值往次小值遍历的时候查找最大值是否发生变化,记录下每次往次小值遍历过程中的极差并取其最小。

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务