推公式
125
#include <iostream>
#include <algorithm>
using namespace std;
/*
整个题的解题思路就是 ,按照w+s排好序,然后在计算出 最大值即可
*/
typedef pair<int, int> PII;
const int N = 50010; //1≤N≤50000,
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}; //w表示 牛的 重量
}
sort(cow, cow + n);
int res = -2e9, sum = 0; //其中s的取值范围就是1≤Si≤1,000,000,000
for (int i = 0; i < n; i ++ ) //sum表示压在该头牛上的 所有牛 的重量
{
int s = cow[i].first - cow[i].second, w = cow[i].second; //s表示第i头牛的强壮度,w表示第i头牛的重量
res = max(res, sum - s);
sum += w; //此时这个w表示上一头牛的重量
}
printf("%d\n", res);
return 0;
}
绝对值不等式
AcWing 104. 货仓选址
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=100100;
int n;
int a[maxn];
int main()
{
cin >> n;
for(int i=0; i<n; i++)
cin >> a[i];
sort(a,a+n);
int res=0;
for(int i=0; i<n; i++)
res+=abs(a[i]-a[n/2]);
cout << res << endl;
return 0;
}
3167. 星星还是树(二维)
#include<iostream>
#include<cmath>
using namespace std;
const int maxn=10010;
const double eps=1e-4; //注意1e-4用double来存储
int n;
double x[maxn],y[maxn];
double dis1(double x1, double y1) //x1,y1就是 要选择的点
{
double sum = 0.0;
for(int i=0;i<n;i++) //统计从(x1,y1)出发到所有点的距离之和
{
sum += sqrt((x[i] - x1)*(x[i] - x1) + (y[i] - y1) * (y[i] - y1));
}
return sum;
}
double dis(double x1) //这个x就是 选择的x坐标
{
double l = 0.0, r = 10000.0;
while(r - l >= eps){
double margin = (r - l)/3.0; //这是对y轴进行3分
double m1 = l + margin;
double m2 = m1 + margin;
if(dis1(x1, m1) <= dis1(x1, m2)) r = m2;
else l = m1;
}
return dis1(x1, r); //x1表示之前 选择的 横坐标,r表示 目前选择的纵坐标
}
int main()
{
scanf("%d", &n);
for(int i=0;i<n;i++){
scanf("%lf%lf", &x[i], &y[i]); //输入x,y坐标轴
}
double l = 0.0, r = 10000.0; //r取10000,是因为x,y的范围 0≤xi,yi≤10000
while(r - l >= eps){ //eps设置为1e-4,表示l与r之间的距离无限接近
double margin = (r - l) / 3.0; //margin相当于 3分后 中间的 参数
double m1 = l + margin; //m1表示三分后的 第1段的最右边的端点
double m2 = m1 + margin; //m2表示三分后的 第2段的最右边的端点
if(dis(m1) <= dis(m2)) r = m2; //表示从m1出发,到其他点的距离更小,则让r=m2
else l = m1; //否则就是 l=m1
}
printf("%d", (int)(dis(r)+0.5)); //4舍5入 的算法就是+0.5
return 0;
}
排序不等式
排队打水
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100010;
int n;
typedef long long LL; //因为n是100000,就算是 每个人的打水时间为1s,则总时间为1+2+3+....+99999 为50亿,而int范围是20亿,所以res必须用long long类型
int a[maxn];
int main()
{
cin >> n;
for(int i=0; i<n; i++)
cin >> a[i];
sort(a,a+n);
LL res=0;
for(int i=0; i<n; i++)
res+=a[i]*(n-i-1);
printf("%lld",res);
return 0;
}
哈夫曼树
合并果子
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int main()
{
int n;
scanf("%d", &n);
priority_queue<int, vector<int>, greater<int>> heap; //小根堆
// priority_queue<int, vector<int>, less<int>> heap; 大根堆
while (n -- )
{
int x;
scanf("%d", &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;
}
区间问题
区间覆盖
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
struct Range
{
int l, r;
bool operator< (const Range &W)const //按照左端点的升序排列
{
return l < W.l;
}
}range[N];
int main()
{
int st, ed;
scanf("%d%d", &st, &ed); //输入一个起点和终点
scanf("%d", &n); //再输入n个区间
for (int i = 0; i < n; i ++ )
{
int l, r;
scanf("%d%d", &l, &r); //输入区间段的左右端点
range[i] = {l, r};
}
sort(range, range + n); //排序
int res = 0; //res表示的是 最后所选的区段的 个数
bool success = false; //success表示 是否成功,初始化为false
for (int i = 0; i < n; i ++ ) //遍历n个区间段
{
int j = i, r = -2e9; //注意r的值是-2e9,其中−109≤ai≤bi≤109,
while (j < n && range[j].l <= st) //j表示哪个区间,r表示所能覆盖左端点的 区间段的最大右区间
{
r = max(r, range[j].r);
j ++ ;
}
if (r < st) //如果r直接小于st,则表示没有
{
res = -1; //标记res为-1
break;
}
res ++ ; //否则就直接 标记 所选择了一个 区间段
if (r >= ed) //如果r大于等于终点,直接标记success为true,然后直接退出循环
{
success = true;
break;
}
st = r; //将start更新为右端点最大值
i = j - 1; //因为在上面 找到的j会向后++,但是下面i的值又会自增,所以必须将i=j-1
}
if (!success) res = -1;
printf("%d\n", res);
return 0;
}
区间分组
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010;
int n;
struct Range
{
int l, r;
bool operator< (const Range &W)const
{
return l < W.l;
}
}range[N];
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ )
{
int l, r;
scanf("%d%d", &l, &r);
range[i] = {l, r};
}
sort(range, range + n);
priority_queue<int, vector<int>, greater<int>> heap; //为什么要用小根堆存放?
for (int i = 0; i < n; i ++ )
{
auto r = range[i]; // r表示当前所判断的区间
if (heap.empty() || heap.top() >= r.l) //heap.top()应该表示所有组的右端点的最小值
heap.push(r.r); //表示需要将r放到一个新的组中
else //将r放到原先的组中,同时也就更新了每个组的最右边的值
{
heap.pop();
heap.push(r.r);
}
}
printf("%d\n", heap.size());
return 0;
}
最大不相交区间数量
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100010;
int n;
struct node
{
int l,r;
bool operator<(const node &t) const
{
return r<t.r;
}
}Node[maxn];
int main()
{
cin >> n;
for(int i=0; i<n; i++)
{
cin >> Node[i].l >> Node[i].r;
}
sort(Node,Node+n);
int res=0,ed=-1e9;
for(int i=0; i<n; i++)
{
if(ed<Node[i].l)
{
ed=Node[i].r;
res++;
}
}
cout << res;
return 0;
}
区间选点
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100010;
int n;
struct node
{
int l,r;
bool operator<(const node &t) const
{
return r<t.r;
}
}Node[maxn];
int main()
{
cin >> n;
for(int i=0; i<n; i++)
cin >> Node[i].l >> Node[i].r;
sort(Node,Node+n);
int res=0,ed=-1e9;
for(int i=0; i<n; i++)
{
if(ed<Node[i].l)
{
res++;
ed=Node[i].r;
}
}
cout << res;
return 0;
}