ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
P1090 合并果子
题目链接:https://www.luogu.org/problemnew/show/P1090
题解:每次取最小的两个进行合并
#include
#define fo(i,j,n) for(register int i=j;i<=n;++i)
#define ll long long
using namespace std;
priority_queue<int, vector<int>, greater<int>> pq;
int n,a,b;
int main(){
scanf("%d",&n);
fo(i,1,n){
scanf("%d",&a);
pq.push(a);
}
ll ans = 0;
fo(i,1,n-1){
a=pq.top();pq.pop();
b=pq.top();pq.pop();
ans += a+b;
pq.push(a+b);
}
printf("%lld\n", ans);
return 0;
}
P1181 数列分段Section I
题目链接:https://www.luogu.org/problemnew/show/P1181
解法一:从左到右倍增直到区间不能再增大为止
解法二:贪心,从左到右一直加到不满足为止,然后重新加
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int maxn = 1e5+5;
int n,m,a[maxn],sum[maxn];
void solve(){
int l=1,p=1,r=l,ans=0;
while(l<=n){
ans++;
r=l,p=1;
while(p){
if(r+p>n){
p >>= 1;continue;
}
if(sum[r+p]-sum[l-1]<=m){
r += p;
p <<= 1;
}else{
p >>= 1;
}
}
l = r+1;
// cout<
}
printf("%d\n",ans);
}
void solve1(){
int ans=1,s=0,x;
fo(i,1,n){
scanf("%d",&x);
if(s+x<=m){
s+=x;
}else{
ans++;
s=x;
}
}
printf("%d\n",ans);
}
int main(){
scanf("%d%d",&n,&m);
// fo(i,1,n)scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
// solve(); // 倍增法,复习一下
solve1();// 直接倍增
return 0;
}
P1208 [USACO1.3]混合牛奶 Mixing Milk
题目链接:https://www.luogu.org/problemnew/show/P1208
题解:每次选便宜的牛奶购买
#include
#define ll long long
#define mk make_pair
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int n,m;
vector<pair<int,int> > ver;
void solve(){
sort(ver.begin(),ver.end());
ll ans=0,all=0;
for(auto p:ver){
if(all+p.second<=n){
ans += p.first*p.second;
all += p.second;
}else{
ans += (n-all)*p.first;
break;
}
}
printf("%lld\n",ans);
}
int main(){
scanf("%d%d",&n,&m);
int a,b;
fo(i,1,m){
scanf("%d%d",&a,&b);
ver.push_back(mk(a,b));
}
solve();
return 0;
}
P1223 排队接水
题目链接:https://www.luogu.org/problemnew/show/P1223
题解:
微扰法证明:
要使总等待时间最少,每一次接水的是还没接水的人中(m人)接水时间t1最少的
这时的后面的人的总等待时间为(m-1)t1,由于ti最小,则该局面下的总等待时间最小
设后面的某个人的等待时间为tk(tk>t1),排第k位(k>1)
这后面的人等待该人的总等待时间为 tk(m-k)
等待 这两个人的总等待时间为 (m-1)t1+(m-k)tk = m(t1+tk) - t1-ktk = T1
若交换两人位置,等待两人的总等待时间为 (m-1)tk+(m-k)t1 = m(t1+tk) - tk-kt1 = Tk
TK-T1 = -tk - kt1 + t1 + ktk = (k-1)*tk - (k-1)t1 = (k-1)(tk-t1)>0
所以任意非位置一(接水时间最少)的位置k,与位置一交换都会使得总等待时间变长
证毕。
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
#define mk make_pair
using namespace std;
int n;
vector<pair<int,int> > ver;
int main(){
scanf("%d",&n);
int x;
fo(i,1,n){
scanf("%d",&x);
ver.push_back(mk(x,i));
}
sort(ver.begin(),ver.end());//当ti重复时,按照输入顺序即可(sort是可以的)
double sum=0.0,all=0.0;
fo(i,0,n-1){
all+=sum; // 加上ver[i].second,这位同学的等待时间
sum+=ver[i].first;// 计算下一位同学的等待时间
printf("%d%c",ver[i].second,i==n-1?'\n':' ');
}
printf("%.2f\n",all/n);
return 0;
}
P1094 纪念品分组
题目链接:https://www.luogu.org/problemnew/show/P1094
解法:每次选择最大的那一个看是否有一个能与它配对成功的,显然可能性最大一点是最小的那一个
#include
#define fo(i,j,n) for(register int i=j; i<=n;++i)
using namespace std;
int m,n,a[30005];
int main(){
scanf("%d%d",&m,&n);
fo(i,1,n)scanf("%d",&a[i]);
sort(a+1,a+1+n);
int ans=0,l=1,r=n;
while(l<=r){
if(a[r]+a[l]<=m){
r--;l++;
ans++;
}else{
r--; ans++;
}
}
printf("%d\n",ans);
}
P1803 凌乱的yyy / 线段覆盖
题目链接:https://www.luogu.org/problemnew/show/P1803
解法:右端点进行排序,每次选择右端点尽量小的,如果该区间可以选择的话,否则继续选择其他右端点尽量小的
#include
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
#define mk make_pair
using namespace std;
int n;
vector<pair<int,int> > ver;
int main(){
scanf("%d",&n);
int a,b;
fo(i,1,n)scanf("%d%d",&a,&b),ver.push_back(mk(b,a));
sort(ver.begin(),ver.end());
int ans = 0,last=0;
fo(i,0,n-1){
if(ver[i].second>=last){
last=ver[i].first;
ans++;
}
}
printf("%d\n",ans);
return 0;
}