// Vijos / 题库 /
水王争霸
sort在结构体排序中,可自定义。之前也知道可自定义,但没想到范围应用这么广!!!
这道题,长见识了。刚开始自定义排序,目前还没找到错误,但就是没过。。。
#include<iostream> #include<queue> #include<cstring> #include<algorithm> using namespace std; #define maxn 11000 struct BigNum { int len; char num[maxn]; char ID[maxn]; }n[maxn]; bool compare(BigNum a,BigNum b) { if(a.len>b.len) return a.len>b.len; if(a.len==b.len){ if(strcmp(a.num,b.num)==0){ return strcmp(a.ID,b.ID)<0; } else return strcmp(a.num,b.num)>0; } return false; } int main() { int m; cin>>m; for(int i=1;i<=m;i++) {
cin>>n[i].ID>>n[i].num; for(int j=0;n[i].num[j]!='\0';j++,n[i].len++); } sort(n+1,n+1+m,compare); for(int i=1;i<=m;i++) cout<<n[i].ID<<endl; return 0; }
国王游戏
//贪心还不是很熟,回来再学习一下。这道题需要用贪心来证明一下
大佬写的证明,之前牛客网上一道题也是类似的证明:
vijos题解的第一版就是这位大佬写的证明,引用一下(证明可以学习一下,下一道题就把牛客上的题目引用一下):
###贪心证明
假设相邻的两个人左右手分别是(a, b), (A, B)。设a * b <= A * B,i之前所有人的左手乘积为S。i+1位置(A,B), i位置为(a,b)
则,ans1 = max{S / b, S * a / B}
若交换
则,ans2 = max{S / B, S * A / b}
因为,a * b <= A * B
所以,S * a / B <= S * A / b
又因为,S / B <= S * a / B
所以,ans2 = S * A / b
ans1 = max{S / B[i], S * a / B}
所以,ans1 <= ans2
所以需要排序,自定义排序+sort
再根据数据的范围来确定,n<=1000,a,b<=10000,数据的乘积最大值为10^12,所以高精*低精+高精除以低精
老实说,这道题可折煞我了;有人说这是道水题,但我还是涨知识了。学到了。。
刚开始看到贪心证明之后,没考虑那么多,直接以为最后一个就是解,殊不知最优解可能也在中间。~~~
#include<iostream> #include<queue> #include<cstring> #include<algorithm> using namespace std; #define maxn 11000 #define p 1e9 struct BigNum { long long left,right; }n[maxn]; long long m,max1[maxn]; struct Big{ int len; int num[maxn]; }; Big a,b,ans; bool compare(BigNum x,BigNum y) { return x.left*x.right<y.left*y.right; }//sort比较,进行排序 void multi(int h) { for(int i=0;i<a.len;i++) a.num[i]=a.num[i]*h; for(int i=0;i<a.len;i++) { a.num[i+1]+=a.num[i]/10; a.num[i]%=10; if(i==a.len-1&&a.num[i+1]) ++a.len; } }//高精乘以低精 void dev(int h) { int t=0; ans.len=a.len; for(int i=ans.len-1;i>=0;i--) { t=t*10+a.num[i]; ans.num[i]=t/h; t=t%h; } while(ans.len>1&&!ans.num[ans.len-1]) --ans.len; }//高精除以低精 bool com(Big x,Big y) { if(x.len<y.len) return 1; if(x.len==y.len) { for(int i=x.len-1;i>=0;i--) if(x.num[i]<y.num[i]) return 1; } return false; }//解也可能在中间,就需要进行比较 int main() { cin>>m;cin>>n[0].left>>n[0].right; for(int i=1;i<=m;i++) { cin>>n[i].left>>n[i].right; } sort(n+1,n+1+m,compare); int h=n[0].left;//国王在第一位不变 while(h) { a.len++; a.num[a.len-1]=h%10; h=h/10; } for(int i=1;i<m;i++)//寻找最优解 { multi(n[i].left); dev(n[i+1].right); if(com(b,ans)) { b.len=ans.len; for(int i=ans.len-1;i>=0;i--) b.num[i]=ans.num[i]; } } for(int i=b.len-1;i>=0;i--) cout<<b.num[i]; return 0; }
//题外题,下面就跟高精无关了,就是个贪心证明
链接:https://ac.nowcoder.com/acm/contest/3003/F
来源:牛客网
题目描述
牛牛和 牛可乐 面前有 n 个物品,这些物品编号为
1,2,…,n1,2,\dots,n1,2,…,n ,每个物品有两个属性 ai,bia_i, b_iai,bi 。
牛牛与 牛可乐会轮流从剩下物品中任意拿走一个, 牛牛先选取。
设 牛牛选取的物品编号集合为 H,牛可乐选取的物品编号的集合为 T,取完之后,牛牛 得分为
∑i∈Hai\sum_{i\in H} a_i∑i∈Hai;而 牛可乐得分为 ∑i∈Tbi\sum_{i\in T} b_i∑i∈Tbi。
牛牛和 牛可乐都希望自己的得分尽量比对方大(即最大化自己与对方得分的差)。
你需要求出两人都使用最优策略的情况下,最终分别会选择哪些物品,若有多种答案或输出顺序,输出任意一种。
看题时自己坑自己,a,b是分别输入
假设牛牛选择ai,bi,牛可乐选择ai+1,bi+1,ai+bi<ai+1+bi+1
同上面的证明
#include<algorithm> #include<iostream> using namespace std; struct bel{ int a,b; int num; }B[1000000]; bool compare(bel x,bel y) { return x.a+x.b>y.a+y.b; }//排序 int main() { int n; cin>>n; for(int i=1;i<=n;i++) B[i].num=i,cin>>B[i].a; for(int i=1;i<=n;i++) cin>>B[i].b; sort(B+1,B+1+n,compare); for(int i=1;i<=n;i+=2) { cout<<B[i].num<<' '; } cout<<endl; for(int i=2;i<=n;i+=2) { cout<<B[i].num<<' '; } return 0; }