2018 ACM-ICPC 亞洲區域賽青島站 E
阿新 • • 發佈:2018-12-20
題意
有n個植物,m次移動1格的機會,
以下n個數a1-an,代表每一次澆水(其實就是訪問),該處的植物會增加防禦值ai,初始防禦值di=0
n個植物分別在座標軸1,…,n的位置,澆水機的位置初始在0,
座標軸無限長,移動1格會耗費1次機會,
從0移動到1上時,會給1這格加上ai,
要求最大化最小值di,輸出di。
題解
二分最後的di,判斷是否可行。
對於每個列舉的結果,不停地在這格和下一格之間移動直至滿足這格的澆水次數,
由於最近且給下一格澆了水,顯然是最優的。
如果總澆水次數超過了m就不是一個可行解,否則就更新下界。
心得
開始沒注意到爆ll,還在那裡求num的累計值。
1e17*1e5顯然爆ll了啊,QAQ中間只要超過m就返回就可以了
還有開始求了一個相當寬的上界sum*m,後來發現也爆ll了,
改成緊上界(m/n+1*maxai)就好了,也沒超過1e17,當然這裡莽一發1e18也能過。
程式碼
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include <map> #include <vector> #include <stack> #include <queue> #include <functional> const int INF=0x3f3f3f3f; const int maxn=1e5+10; const int mod=1e9+7; const int MOD=998244353; const double eps=1e-7; typedef long long ll; #define vi vector<int> #define si set<int> #define pii pair<int,int> #define pi acos(-1.0) #define pb push_back #define mp make_pair #define lowbit(x) (x&(-x)) #define sci(x) scanf("%d",&(x)) #define scll(x) scanf("%lld",&(x)) #define sclf(x) scanf("%lf",&(x)) #define pri(x) printf("%d",(x)) #define rep(i,j,k) for(int i=j;i<=k;++i) #define per(i,j,k) for(int i=j;i>=k;--i) #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; ll t,n,a[maxn],tmp[maxn],m,sum,maax; bool check(ll mid) { ll num=0,last=-1;//上一個澆水位置 rep(i,0,n-1) { tmp[i]=mid/a[i]; if(mid%a[i])tmp[i]++; } rep(i,0,n-1) { if(tmp[i]<=0)continue; num+=(i-last)+2*(tmp[i]-1);//從上一個澆水位置移動到這裡來 if(num>m)return 0;//num可能爆ll last=i; tmp[i+1]-=(tmp[i]-1); } return 1; } ll erfen(ll l,ll r) { while(r-l>1) { ll mid=(l+r)/2; if(check(mid))l=mid; else r=mid; } return l; } int main() { scll(t); while(t--) { maax=0; scll(n),scll(m); rep(i,0,n-1) { scll(a[i]); maax=max(maax,a[i]); sum+=a[i]; } printf("%lld\n",erfen(0,(m/n+1)*maax));//注意上界小心爆ll } return 0; }