[菜鸡的解题报告]牛客小白月赛69 2023.3.24

第一次比赛,总共ac了两个题,卡在第三题搜索上了。。。遂赛后补题

A

题目描述

有 aa 个蛋挞,分给 bb 个人,使得每个人分得蛋挞数量一样且尽量多。这样会导致可能有一些蛋挞没被分走,导致浪费,于是牛牛准备回收这些蛋挞并一口吃下全部。牛牛想知道是自己吃的多还是分蛋挞的每个人吃得多?

如果牛牛吃得多,输出 "niuniu eats more than others",如果分蛋挞的每个人吃得多,输出 "niuniu eats less than others",如果一样多输出 "same"(均不含引号)。

输入描述:

一行两个正整数 a,b(1\le a,b\le 10^{16})a,b(1≤a,b≤10

16

)。

输出描述:

输出一行一个字符串,表示答案。

签到题,做除法然后与原数相减(取余)比较即可。

#include<bits/stdc++.h>
using namespace std;
long long a,b;
int main(){
    cin>>a>>b;
    long long chu=a/b;
    if(a-(chu*b)==chu){
        cout<<"same\n";
    }else{
        if(a-(chu*b)>chu){
            cout<<"niuniu eats more than others\n";
        }else{
            cout<<"niuniu eats less than others\n";
        }
    }
    return 0;
}

B

https://ac.nowcoder.com/acm/contest/52441/B

贪心题,可以显而易见猜出从小到大排序,然后从大到小隔一个用一次优惠劵是最优

#include<bits/stdc++.h>
using namespace std;
int n,a[1000006];

bool cmp(int x,int y){
    return x<y;
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    int j=0;
    long long ans=0;
    sort(a+1,a+1+n,cmp);
    for(int i=n;i>=1;i--){
        j++;
        if(j==1){ans+=a[i];}
        if(j==2){j=0;}
    }
    cout<<ans<<"\n";
    
}

C https://ac.nowcoder.com/acm/contest/52441/C

开始直接写了个搜索,结果tle了。。。实际上直接求全排列再依次找最就行。。。搜索基础还是要加强啊

#include<bits/stdc++.h>
using namespace std;
long long n,t,p;
long long ti[10],si[10],ci[10],bi[10];
int a[10];
int vis[10];
long long ans=0;

void sol(){
    long long time=0;
    long long tt=0;
    for(int i=1;i<=n;i++){
    //    cout<<a[i]<<" ";
        time+=ti[a[i]];
        if(time>t)break;
        tt+=max(si[a[i]]-time*bi[a[i]],ci[a[i]]);
    }
//    cout<<"\n";
    ans=max(tt,ans);
}




void dfs(int num){
    if(num>n){sol();return;    }
    for(int i=1;i<=n;i++){
        if(!vis[i]){
          vis[i]=1;    
          a[num]=i;
          dfs(num+1);
          vis[i]=0;
          a[num]=0;    
        }
    }
}


int main(){
    cin>>n>>t>>p;
    for(int i=1;i<=n;i++){
        int a,b,c,x,y;
        cin>>a>>b>>c>>x>>y;
        ti[i]=x;
        si[i]=a-p*y;
        bi[i]=b;
        ci[i]=c;
    }
    dfs(1);
    cout<<ans<<"\n";
    
    return 0;
}

d https://ac.nowcoder.com/acm/contest/52441/D

题解视频里讲的是二分。。。但是直接贪心应该就行。开始kruskal算法求最小生成树,然后把这个树的边从大到小排序,策略上可以显而易见看出,优先修最大的(因为这时乘的i最小),可以充分利用牛牛的钱,所以依次由大到小找直到发现钱超了,就得到了边界p

注意这个题数据范围有longlong,如果两个int相乘,最后范围大于int的就会崩,long long+=int*int这种就会错误,掉到这个坑里了,long*int则不会

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long c;
int cnt;
struct edge{
  int to1,to2;
  long long dis;    
};
edge e[200002];

int ed[200002];

bool cmp(edge a,edge b){
    return a.dis<b.dis;
}
bool cmp2(int a,int b){
    return a>b;
}

int pre[40003];

int find(int a){
    if(pre[a]==a){return a;}
    else
    {
    pre[a]=find(pre[a]);
    return pre[a];
    }
}

void merge(int a,int b){
    
    
    int x=find(a);
    int y=find(b);
    if(x==y)return;else
    pre[x]=y;
    
}


int main(){
    cin>>n>>m>>c;
    for(int i=1;i<=m;i++){
        int xi,yi,di;
        scanf("%d%d%d",&xi,&yi,&di);
        
        e[i].to1=xi;
        e[i].to2=yi;
        e[i].dis=di;
    }
    
    for(int i=1;i<=n;i++){pre[i]=i;}
    
    sort(e+1,e+1+m,cmp);
    
    int bian=0;
    for(int i=1;i<=m;i++){
        if(find(e[i].to1)!=find(e[i].to2)){
            merge(e[i].to1,e[i].to2);
            bian++;
            ed[bian]=e[i].dis;
            if(bian==n-1)break;
        }
    }
    sort(ed+1,ed+1+n-1,cmp2);
    long long tt=0;
    int f=0;
    for(long long i=1;i<=bian;i++){
        tt+=i*ed[i];//坑
        //cout<<ed[i]<<" ";
        if(tt>c){f=1;cout<<ed[i]<<"\n";break;}
    }
    if(f==0)cout<<0<<"\n";
    
    return 0;
}

e/fhttps://ac.nowcoder.com/acm/contest/52441/F 题面一样就是数据范围不一样

e题数据小,直接暴力枚举就行,

f题需要优化一下,用桶的思想(不好描述,很精妙,看代码),枚举每一个顶点,对每一个顶点枚举每一条边,用桶标记距离,最后去掉直线即可。

注意,整数点是无法产生等边三角形的,所以本题不用管

另外由于有负数坐标,要转化为正的,但是至少要加整个范围长度(1000)以上否则去直线的时候对称一下,对称点会为负导致越界

#include<bits/stdc++.h>
using namespace std;
int zb[3000002];
int vis[3002][3002];
int n;
int ans,line;
struct point{
    int x,y;
};
point p[3002];

int dis(point a,point b){
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&p[i].x);
        scanf("%d",&p[i].y);
        vis[p[i].x+1100][p[i].y+1100]++;
    }
    ans=0;line=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j)continue;
            ans+=zb[dis(p[i],p[j])];
            zb[dis(p[i],p[j])]++;
            if(vis[2*p[i].x-p[j].x+1100][2*p[i].y-p[j].y+1100])line++;
        }
        for(int k=1;k<=n;k++){
            if(i==k)continue;
            zb[dis(p[i],p[k])]=0;
        }
    }
    
    cout<<ans-line/2<<"\n";
    return 0;
}

总结:还得练基础,熟练度,思想!我太菜了

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值