西电2021校赛选拔赛 C.扶梯问题 (贪心,枚举)
-
题意:有\(n\)个人轮流上电梯,电梯送完一个人需要\(1\)个时刻.电梯有待机和运行两种状态,待机每时刻消耗\(E_2\)电量,运行每时刻消耗\(E_1\)电量,若电梯无人使用经过\(k\)个时刻后会变为待机状态,从待机状态变成运行状态需要消耗\(E_3\)电量,你可以自定义\(k\)的值,求出最后一个人走完后的最小消耗总电量.
-
题解:先求出任意两人之间的时间差并排序,假设\(k=0\),如果我们要延长\(k\),该怎么延长?很明显,将两人之间的差填满一定是最优的,这样可以省去一(多,因为可能有很多相同的时间差)次启动的额外电量,如果不是为了贪心减少这一(多)次启动电量,那肯定没必要延长\(k\),那么这题就很简单了,枚举每段时间差,依次填满维护答案.
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int n,k; ll e1,e2,e3; //e1:运行耗电 e2:待机耗电 e3:切换耗电 k:转待机时间 int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); int _; cin>>_; while(_--){ cin>>n>>e1>>e2>>e3; vector<ll> t(n+1); rep(i,1,n) cin>>t[i]; vector<ll> diff(n+1); ll num=n; ll runt=n*(e1-e2); ll k=0; ll mi=1e18; rep(i,2,n){ diff[i]=t[i]-t[i-1]-1; if(diff[i]==0) num--; } sort(diff.begin()+2,diff.end()); mi=min(mi,runt+num*e3); for(int i=2;i<=n;++i){ if(diff[i]==0) continue; int last=i; for(int j=i;j<=n;++j){ if(diff[i]==diff[j]){ last=j; } else break; } runt+=(num-1)*(diff[i]-k)*(e1-e2); k=diff[i]; num-=(last-i)+1; mi=min(mi,runt+num*e3); i=last; } cout<<mi+e2*(t[n]+1); if(_!=0) cout<<'\n'; } return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮