【貪心】小Y的炮[cannon]題解
阿新 • • 發佈:2018-11-03
模擬賽的題目,做的時候由於第二題表打太久了,只剩下40分鐘,想都沒想就寫了一個爆搜20分...
這道題單調性很關鍵,下面會解釋
P.S.解釋在程式碼裡
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<map> using namespace std; typedef long long ll; inline int read(){ int ans=0,f=1;char chr=getchar(); while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();} while(isdigit(chr)) {ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} return ans*f; } inline void kai(){ freopen("cannon.in","r",stdin); freopen("cannon.out","w",stdout); } const int maxn=250004; struct data{ ll a,d; bool operator <(const data &b)const{ return (a<b.a || (a==b.a && d<b.d)); } }cnn[maxn],p[maxn]; ll k,h[maxn],ans=0; int n,m,cnt=0; map<ll,ll>f; int main(){ n=read();m=read();k=read(); for(int i=n;i>=1;--i)h[i]=read(); for(int i=1;i<=m;++i)cnn[i].a=read(),cnn[i].d=read(); sort(cnn+1,cnn+1+m); for(int i=1;i<=m;++i){ while(cnt && p[cnt].d<=cnn[i].d)--cnt; p[++cnt]=cnn[i]; }//貪心刪掉沒有用的炮 /* 這裡的貪心:如果一個炮打的低,能刪掉的山的高度又小,那要它何用呢? */ ll dn=0;f[0]=0; for(int i=1;i<=cnt;++i){ if(i!=1)dn=p[i-1].a; ll l=max(dn,p[i].a-p[i].d); for(ll j=l+1;j<=p[i].a;++j){ ll t=(j-dn-1)/p[i].d+1; f[j]=f[max(0*1ll,j-(p[i].d*t))]+t; } }//處理出高度為x的山最少要刪幾次才行(類似於揹包的做法?) int j=1; dn=0; for(int i=1;i<=n;++i){ while(j<=cnt && p[j].a<h[i])++j;//第i座山用第j個炮,由於遞增,可以一直下去 if(j>cnt)break;//如果當前山都處理不好,那麼後面的山更不行 ,直接結束 if(j!=1)dn=p[j-1].a; ll t=(h[i]-dn-1)/p[j].d+1;//因為單調性,可以直接用上一座山殘留資料 ll q=f[max(0*1ll,h[i]-(p[j].d*t))]+t;//還是類似於揹包 if(k>=q)k-=q,++ans;else break;//如果當前山加不進去,還是不行,結束 } printf("%lld ",ans); printf("%lld",k); }