题意:在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
分析:从给出的个数里每次取两个最小的数相加,并将和放入数列;以下代码借助优先队列
AC代码:
#include
using namespace std;
priority_queue,greater > q;//定义一个优先为小的优先队列
int main()
{
int n,x,a,b,ans=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>x;
q.push(x);
}
for(int i=1;i
##优先队列:
¢头文件: #include
定义:priority_queue
操作:q.push(elem) 将元素elem置入优先队列 q.top() 返回优先队列的下一个元素
q.pop() 移除一个元素 q.size() 返回队列中元素的个数
q.empty() 返回优先队列是否为空
#include
using namespace std;
int a[100010];
int main()
{
int n,m,sum=0,ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
sum+=a[i];
if(sum+a[i+1]>m){ans++;sum=0;}
}
if(sum!=0)ans++;//注意若最后sum不为0,则ans要加一
cout<
注:每天所有奶农的总产量大于Marry乳业的需求量。输入:n需要的牛奶总量,m提供牛奶的农民总数,m个农民分别的牛奶单价及牛奶量
分析:将单价升序排列,由最小单价开始买,注意数组的大小,太大太小都RE#include
using namespace std;
struct milk{
int price;//牛奶单价
int num;//牛奶数量
int value;//花销
}a[5000010];
bool cmp(milk a,milk b)//单价由小到大排序
{
return a.price main()
{
int n,m,money=0,sum=0;//n需要牛奶的总数 m农民数2
cin>>n>>m;
if(n==0||m==0){cout<<0<>a[i].price>>a[i].num;
a[i].value=a[i].price*a[i].num;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
money+=a[i].value;
sum+=a[i].num;
if(sum==n){cout<n){sum-=a[i].num;money-=a[i].value;n-=sum;money+=n*a[i].price;cout<
##cout的格式化输出:#include
using namespace std; struct water { double t; int k; }a[1010]; bool cmp(water c,water b) { return c.t >n; for(int i=1;i<=n;i++) { cin>>a[i].t; a[i].k=i; } sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++) { cout< cout< return 0; } #include
#include using namespace std; int main() { const int p=1.2345678,a=1234678; cout<
5,P1094纪念品分组
题意:元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。
你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。
输入:n纪念品之和上限,m纪念品总数,m个纪念品的价格 输出:最少分组数分析:每组最多两件,排序后,取每次的最大值和最小值组合,若小于等于上限,则分为一组,若大于上限,则说明最大值只能自己一组。
AC代码:
#include
using namespace std; int a[3000010]; void qsort(int l,int r)//快排 { int i,j,mid; i=l;j=r;mid=a[(l+r)/2]; do { while(a[i] mid)j--; if(i<=j) { swap(a[i],a[j]); i++;j--; } }while(i<=j); if(l >n>>m; i=1,j=m; for(int k=1;k<=m;k++) cin>>a[k]; qsort(1,m); while(i<=j) { if(a[i]+a[j]<=n){ans++;i++;j--;}//见分析 else{ans++;j--;} } cout< 6.凌乱的YYY
题意:现在各大oj上有n个比赛,每个比赛的开始、结束的时间点是知道的。yyy认为,参加越多的比赛,noip就能考的越好(假的)所以,他想知道他最多能参加几个比赛。由于yyy是蒟蒻,如果要参加一个比赛必须善始善终,而且不能同时参加2个及以上的比赛。 输入:活动个数n 输出:n个活动的起始时间和结束时间
分析:将活动结束时间升序排序,判断每个结束时间是否与前一个起始时间重合
AC代码:
超时代码:#include
using namespace std; int n,begin[1000010],end[1000010]; void init()//输入函数 { cin>>n; for(int i=1;i<=n;i++) cin>>begin[i]>>end[i]; } void qsort(int x,int y)//快排 { int i,j,mid,t; i=x;j=y;mid=end[(x+y)/2]; while(i<=j) { while(end[i] mid)j--; if(i<=j) { swap(end[i],end[j]); swap(begin[i],begin[j]); i++;j--; } } if(x void solve()//处理 { int ans=0,t=-1; for(int i=1;i<=n;i++) if(begin[i]>=t){ans++;t=end[i];} cout< int main() { init(); qsort(1,n); solve(); return 0; } #include
using namespace std; struct time{ //定义时间结构体 int begin; int end; }a[1000010]; void qsort(int l,int r)//快排 { int i,j,mid; i=l;j=r;mid=a[(l+r)/2].end; do{ while(a[i].end mid)j--; if(i<=j) { swap(a[i].end,a[j].end); i++;j--; } }while(i<=j); while(l >n; for(int i=1;i<=n;i++) cin>>a[i].begin>>a[i].end;//输入起始时间和结束时间 qsort(1,n);//对结束时间进行升序排序 int ans=0,t=-1;//令t=-1可以使第一个区间与其他区间操作相同 for(int i=1;i<=n;i++) if(a[i].begin>=t){ans++;t=a[i].end;} cout< 7.P1031均分纸牌
题意:有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若干张纸牌,然后移动。
移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。
分析:求总张数--->求平均数--->求各堆纸牌与平均数的差值--->左往右加(注意去除前导后导0,及中间0的判断)AC代码:
#include
using namespace std; int a[110]; int main() { int n,ave=0; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; ave+=a[i];//求总张数 } ave/=n;//求平均数 for(int i=1;i<=n;i++) a[i]-=ave;//求每堆纸牌与平均数差值 int i=1,j=n,step=0; while(a[i]==0&&i 1)j--;//去除前导后导0 while(i 8,P1080国王游戏
题意:恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
输入格式:第一行包含一个整数 n,表示大臣的人数。第二行包含两个整数 a和 b,之间用一个空格隔开,分别表示国王左手和右手上的整数。接下来 n 行,每行包含两个整数 a 和 b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。输出格式:输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。 分析:(抄袭)
我们对于国王身后的两个点来分析
队列可能是这样的:
* Left Right king: a0 b0 p1 a1 b1 p2 a2 b2 那么我们计算可得ans1 =max(b1 a0,b2 a0∗a1)
队列也有可能是这样的
* Left Right king: a0 b0 p2 a2 b2 p1 a1 b1 那么我们计算可得ans2 =max(b2 a0,b1 a0∗a2)
我们来对比一下两个答案:
ans1 =max(b1 a0,b2 a0∗a1)
ans2 =max(b2 a0,b1 a0∗a2)
可以替换得:
ans1 =max(k1,k2)
ans2 =max(k3,k4)
显然我们可以得到:
b2 a0∗a1 >b2 a0
b1 a0∗a2 >b1 a0
即: k2 >k3
k4 >k1
如果ans1 <ans2
那么易得:
k4>k2
即: b1 a0∗a2 >b2 a0∗a1
变形可得:
当ans1 <ans2 的结论 时,我们也能够得到
所以,为了ans 取到最小值,我们需要将ai∗bi 较小的放在前面
那么我们以ai∗bi 为关键字排序即可
同时,统计答案时一定不要忘了写高精度!
AC代码:#include
using namespace std; int n,l=1,a[100010],b[100010],c[100010],g[1000010]; //l表示高精度中字符串的长度 //a表示乘积,b表示左手,c表示右手 void gj1(int x) //高精乘 { for(int i=1;i<=l;i++) g[i]*=b[x]; //每一个都乘 for(int i=1;i<=l;i++) { g[i+1]+=(g[i]/10); //进位 g[i]%=10; //进位后处理 } l++; //长度加一 while(g[l]>9) { g[l+1]+=(g[l]/10); //单个位上>9 进位 g[l]%=10; //进位后处理 l++; //长度加一 } if(g[l]==0) l--; //数组末位(数的首位)为0,出数组 } void gj2() //高精除 { for(int i=l;i>=1;i--) { g[i-1]+=((g[i]%c[n])*10); //将前一位%第n位大臣右手给下一位(对于数来说) g[i]/=c[n]; //处理这一位 } while(g[l]==0) l--; //处理首位 if(l==0) printf("1\n"); //防止减完(测试点2) } void qsort(int l,int r) //快排 { int i=l,j=r,mid=a[(l+r)/2]; while(i<=j) { while(a[i] mid) j--; if(i<=j) { swap(a[i],a[j]); swap(b[i],b[j]); swap(c[i],c[j]); //每个人对应的三个数组都要跟着换 i++; j--; } } if(l >n; cin>>b[0]>>c[0]; //读入国王,国王不参与排序,所以‘0’ for(int i=1;i<=n;i++) //读入大臣,并计算左手*右手 { cin>>b[i]>>c[i]; a[i]=b[i]*c[i]; } qsort(1,n); //排序 g[1]=b[0]; //从国王左手开始乘,赋初值 for(int i=1;i =1;i--) cout<