第一次比赛,总共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;
}
总结:还得练基础,熟练度,思想!我太菜了