中石大第39次CSP培训Week5题解
A.排队接水
Key:贪心
题目要求说要平均等待时间最短,也就是总等待时间最短。所以令接水需求最小的人排在前面,最大的排在后面。
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define int int long long
#define pb push_back
#define bs bitset
#define val(a) (a<'a' ? (a-'A'+'a') : a)
#define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
typedef pair<char,int> PCI;
typedef pair<int,int> PII;
typedef pair<long long, long long> PLL;
typedef priority_queue<int> PQ;
typedef priority_queue<int, vector<int>, greater<int>> Q;
const int N = 2e5+10, MAX = 1e9, INF = -1e9;
int n;
PII a[N];
double ans=0;
void solve(){
cin>>n;a[0]={0,0};
for(int i=1;i<=n;i++)cin>>a[i].first,a[i].second=i;
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)a[i].first+=a[i-1].first,cout<<a[i].second<<" ";
cout<<endl;
for(int i=1;i<=n;i++)ans+=a[i-1].first*1.0;
printf("%.2lf",ans/n*1.0);
return ;
}
signed main()
{
fast();
int t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
B.合并果子
Key:贪心+最小堆
每次合并剩余堆中最小的两堆
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define int int long long
#define pb push_back
#define bs bitset
#define val(a) (a<'a' ? (a-'A'+'a') : a)
#define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
typedef pair<char,int> PCI;
typedef pair<int,int> PII;
typedef pair<long long, long long> PLL;
typedef priority_queue<int> PQ;
typedef priority_queue<int, vector<int>, greater<int>> Q;
const int N = 2e5+10, MAX = 1e9, INF = -1e9;
int n;
int e;
int ans=0;
Q q;
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>e;
q.push(e);
}
while(q.size()>=2){
int a=q.top();q.pop();
int b=q.top();q.pop();
ans+=a+b;
q.push(a+b);
}
cout<<ans<<endl;
return ;
}
signed main()
{
fast();
int t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
C.平均分配
Key:排序
计算出小B和小C两种价格的差并排序,前n个给小B,剩余给小C
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define int int long long
#define pb push_back
#define bs bitset
#define val(a) (a<'a' ? (a-'A'+'a') : a)
#define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
typedef pair<char,int> PCI;
typedef pair<int,int> PII;
typedef pair<long long, long long> PLL;
typedef priority_queue<int> PQ;
typedef priority_queue<int, vector<int>, greater<int>> Q;
const int N = 2e5+10, MAX = 1e9, INF = -1e9;
int n;
vector<PII> v(N);
int ans=0;
bool cmp(PII x,PII y){
if(x.first!=y.first)return x.first>y.first;
else return x.second>y.second;
}
void solve(){
cin>>n;
for(int i=1;i<=2*n;i++)cin>>v[i].second;
for(int i=1;i<=2*n;i++){
cin>>v[i].first;
v[i].first=v[i].second-v[i].first;
}
sort(v.begin()+1,v.begin()+2*n+1,cmp);
for(int i=1;i<=n;i++)ans+=v[i].second;
for(int i=n+1;i<=2*n;i++)ans+=v[i].second-v[i].first;
cout<<ans<<endl;
return ;
}
signed main()
{
fast();
int t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
D.第34次CSP认证第二题:矩阵重塑(其二)
Key:技巧—矩阵的一维压缩
重塑操作对于一维压缩的矩阵修改为 \(O(1)\),只需要修改 \(m\) 和 \(n\) 。
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define int int long long
#define pb push_back
#define bs bitset
#define val(a) (a<'a' ? (a-'A'+'a') : a)
#define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
typedef pair<char,int> PCI;
typedef pair<int,int> PII;
typedef pair<long long, long long> PLL;
typedef priority_queue<int> PQ;
typedef priority_queue<int, vector<int>, greater<int>> Q;
const int N = 1e4+10, MAX = 1e8, INF = -1e9;
int a[N];
int g[N][N];
int m,n;
int q;
void f1(int x,int y){
n=x;
m=y;
}
void f2(){
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
g[i][j]=a[(j-1)*m+i];
}
}
swap(m,n);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[(i-1)*m+j]=g[i][j];
}
}
}
void solve(){
cin>>n>>m>>q;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[(i-1)*m+j];
}
}
int op,x,y;
while(q--){
cin>>op>>x>>y;
if(op==1)f1(x,y);
else if(op==2)f2();
else cout<<a[x*m+y+1]<<endl;//二维数组的一维压缩
}
return ;
}
signed main()
{
fast();
int t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
E.My Cow Ate My Homework S
Key:最小后缀数组+后缀和
逆向预处理出后缀和和最小值直接计算平均值
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define int int long long
#define pb push_back
#define bs bitset
#define val(a) (a<'a' ? (a-'A'+'a') : a)
#define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
typedef pair<char,int> PCI;
typedef pair<int,int> PII;
typedef pair<long long, long long> PLL;
typedef priority_queue<int> PQ;
typedef priority_queue<int, vector<int>, greater<int>> Q;
const int N = 2e5+10, MAX = 1e9, INF = -1e9;
int n;
double a[N];
double s[N];
double lost[N];
double ave[N];
double top=-1;
void solve(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
lost[n+1]=MAX;s[n+1]=0;
for(int i=n;i>=2;i--){
lost[i]=min(lost[i+1],a[i]);
s[i]=s[i+1]+a[i];
if(i!=n)ave[i]=((s[i]-lost[i])/(n-i))*1.0,top=max(top,ave[i]);
}
for(int i=2;i<=n-1;i++){
if(top==ave[i])cout<<i-1<<endl;
}
return ;
}
signed main()
{
fast();
int t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
F.第36次CSP认证第二题:梦境巡查
Key:前缀和+后缀最大数组
每次计算和的时候用前缀和优化,最后多出的代价就是原本的最大值和后缀中的最大值+ \(c\) ,预处理出后缀最大值即可优化到 \(O(n)\)
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define int int long long
#define pb push_back
#define bs bitset
#define val(a) (a<'a' ? (a-'A'+'a') : a)
#define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
typedef pair<char,int> PCI;
typedef pair<int,int> PII;
typedef pair<long long, long long> PLL;
typedef priority_queue<int> PQ;
typedef priority_queue<int, vector<int>, greater<int>> Q;
const int N = 1e5+10, MAX = 1e8, INF = -1e9;
int n;
int a[N];
int b[N];
int c[N];
int e=0;
int suma=0;int sumb=0;
void solve(){
cin>>n;
for(int i=0;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
b[0]=0;
for(int i=1;i<=n+1;i++){
suma+=a[i-1];sumb+=b[i-1];
c[i]=max(0ll,suma-sumb);
e=max(e,c[i]);
}
stack<int> ans;
for(int i=n+1;i>=1;i--){
c[i]=max(c[i+1],c[i]);
int x=max(e,c[i]+b[i-1]);
x=min(suma,x);
ans.push(x);
}
ans.pop();
while(!ans.empty()){
cout<<ans.top()<<" ";
ans.pop();
}
return ;
}
signed main()
{
fast();
int t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
G.怪物
Key:贪心,二分,排序
我们来想想贪心的策略,首先,我们很显然的可以想到一个解法:在有怪物地雷肯定是要引爆的。计算每一只怪物移动到附近地雷的代价(加上引爆代价),如果它小于等于这只怪物的生命值 \(h[i]\) ,那么我们就选择移动并引爆,否则直接敲死即可。但是,这样明显是错误的,我们不应该将怪物移动到地雷上就引爆,应该看看有没有其他怪物也要移动到这里,一起引爆,能省更多的钱,那么我们就需要定义一个数组 \(st\) 来表示这里是否已经有怪物了。至于为啥是小于等于 \(h[i]\) 呢,原因是你占一个地雷说不定可以让其他怪物更少花费便可以被杀死。而判断移动到附近地雷的代价,我们只要将 \(x\) 排序,使用 \(lower bound\) 即可。这种怪物处于中间(并且两边移动花费(包括引爆费用)相同,移动花费小于怪物生命值)的情况又怎么办呢?哦,我们应该将怪物的位置也进行排序,这样,前面的已经全部处理完了,我们只需要考虑后面的!
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define int int long long
#define pb push_back
#define bs bitset
#define val(a) (a<'a' ? (a-'A'+'a') : a)
#define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
typedef pair<char,int> PCI;
typedef pair<int,int> PII;
typedef pair<long long, long long> PLL;
typedef priority_queue<int> PQ;
typedef priority_queue<int, vector<int>, greater<int>> Q;
const int N = 2e5+10, MAX = 1e18, INF = -1e18;
int n,k;
PII a[N];
int x[N];
PII moves[N];
bool st[N];
bool ben[N];
int ans=0;
void solve(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i].first>>a[i].second;
}
for(int i=1;i<=k;i++){
cin>>x[i];
}
sort(x+1,x+1+k);
sort(a+1,a+1+n);
x[0]=INF;x[k+1]=MAX;
for(int i=1;i<=n;i++){
int t=lower_bound(x,x+k+2,a[i].first)-x;
int d1=abs(x[t]-a[i].first);
int d2=abs(x[t-1]-a[i].first);
if(d1<=d2){
moves[i].first=t;
moves[i].second=d1;
}
else{
moves[i].first=t-1;
moves[i].second=d2;
}
if(d1==d2)ben[i]=true;
}
for(int i=1;i<=n;i++){
if(moves[i].second+1<=a[i].second){
ans+=moves[i].second;
if(ben[i]&&st[moves[i].first-1])continue;
else st[moves[i].first]=true;
}
else ans+=a[i].second;
}
for(int i=1;i<=k;i++){
if(st[i])ans++;
}
cout<<ans<<endl;
return ;
}
signed main()
{
fast();
int t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}