1.合并果子
【哈夫曼树】
#include <bits/stdc++.h>
using namespace std;
int n;
int main()
{
cin>>n;
priority_queue<int, vector<int >,greater<int> >heap;
int x;
while(n--)
{
cin>>x;
heap.push(x);
}
int res=0;
while(heap.size()>1)
{
int a=heap.top();heap.pop();
int b=heap.top();heap.pop();
res+=a+b;
heap.push(a+b);
}
printf("%d\n",res);
return 0;
}
2.耍杂技的牛
结论:按照wi+si从小到大的顺序排,得到的最大危险系数一定最小
#include <bits/stdc++.h>
using namespace std;
typedef pair<int ,int> PII;
const int N=50010;
int n;
PII cow[N];
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int s,w;
scanf("%d%d",&w,&s);
cow[i]={w+s,w};
}
sort(cow,cow+n);//pair按照第一位排序
int res=-2e9,sum=0;
for(int i=0;i<n;i++)
{
int s=cow[i].first-cow[i].second,w=cow[i].second;
res=max(res,sum-s);
sum+=w;
}
printf("%d\n",res);
return 0;
}
3.1055. 股票买卖 II
买股票的贪心策略:看相邻两天,如果后一天>前一天,则交易一次
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
int price[N];
int n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&price[i]);
int cnt=0;
for(int i=1;i+1<=n;i++)
{
int dt=price[i+1]-price[i];
if(dt>0) cnt+=dt;
}
printf("%d\n",cnt);
return 0;
}
4.122. 糖果传递
需要一系列的推到证明转化成仓库选址的模型
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1000010;
int n;
int a[N];
LL c[N];
int main()
{
scanf("%d",&n);
LL sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
//sum变成平均数,下面c[i]的步骤按照推导过程来求
sum/=n;
for(int i=n;i>1;i--)
{
c[i]=c[i+1]+sum-a[i];
}
c[1]=0;
//仓库选址中的求各个点到中位数距离的步骤
sort(c+1,c+n+1);
LL res=0;
for(int i=1;i<=n;i++) res+=abs(c[i]-c[(n+1)/2]);
printf("%lld\n",res);
return 0;
}
5.1235.付账问题
贪心策略:将每个同学手里的钱排序,如果<平均值,就有多少付多少,不足的平摊到剩下比他大的所有同学身上;如果>平均值,就付平均值
#include <bits/stdc++.h>
using namespace std;
const int N=500010;
int n;
int a[N];
int main()
{
long double s;
cin>>n>>s;
for(int i=0;i<n;i++) scanf("%d",&a[i]);
sort(a,a+n);
long double res=0,avg=s/n;
for(int i=0;i<n;i++)
{
double cur=s/(n-i);
if(a[i]<cur) cur=a[i];
res+=(cur-avg)*(cur-avg);
s-=cur;
}
printf("%.4lf\n",sqrt(res/n));
return 0;
}
6.1239. 乘积最大
#include <bits/stdc++.h>
using namespace std;
const int N=100010,mod=1000000009;
int n,k;
int a[N];
typedef long long LL;
int main()
{
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
sort(a,a+n);
int res=1;
int l=0,r=n-1;
int sign=1;//定义符号
if(k%2)//先判断特殊情况即k为奇数
{
res=a[r--];//取出最大的一个负数
k--;
if(res<0)//所有数均为负数的情况
sign=-1;
}
while(k)
{
LL x=(LL)a[l]*a[l+1],y=(LL)a[r-1]*a[r];//左右两侧均成对取数
//哪边大取哪边
if(x*sign>y*sign)
{
res=x%mod*res%mod;
l+=2;
}
else
{
res=y%mod*res%mod;
r-=2;
}
k-=2;
}
printf("%d\n",res);
return 0;
}
7.1248.灵能传递
超级难,我只是刚刚看懂/(ㄒoㄒ)/~~
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=300010;
int n;
LL a[N],s[N];
bool st[N];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
s[0]=0;
for(int i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
s[i]=s[i-1]+a[i];
}
LL s0=s[0],sn=s[n];
if(s0>sn)
swap(s0,sn);
sort(s,s+n+1);
//寻找s0和sn的位置
for(int i=0; i<=n; i++)
if(s[i]==s0)
{
s0=i;
break;
}
for(int i=n; i>=0; i--)
if(s[i]==sn)
{
sn=i;
break;
}
memset(st, 0,sizeof st);//判断当前点是否被用过
//按照s0——>最小值——>最大值——>sn的顺序重构前缀和数组
//使得相邻两项前缀和的差值a[i]最大
int l=0,r=n;
for(int i=s0;i>=0;i-=2)//所谓的隔一个一跳
{
a[l++]=s[i];
st[i]=true;
}
for(int i=sn;i<=n;i+=2)
{
a[r--]=s[i];
st[i]=true;
}
for(int i=0;i<=n;i++)
if(!st[i]) a[l++]=s[i];
LL res=0;
for(int i=1;i<=n;i++)
res=max(res,abs(a[i]-a[i-1]));
printf("%lld\n",res);
}
return 0;
}