1. 程式人生 > >【三分】【貪心】TCO2016R1B SettingShield

【三分】【貪心】TCO2016R1B SettingShield

題意:

在這裡插入圖片描述


分析:

很顯然,以第一種方式的使用次數為自變數,以第二種方式的使用次數為因變數,一定是一個不上升函式。
換言之,已知f(x)為不下降函式,通過神奇的證明發現:f(x)+x為單谷函式。
所以。。。三分就行了第一種方式的使用次數就行了。。
求總方案可以用貪心的思想:從左往右依次處理每個位置,求出覆蓋當前位置的最遠點。如果要在當前位置加值,則每次都加到最遠點為止。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include
<vector>
#define SF scanf #define PF printf #define MAXN 100010 #define INF 1000000000000000ll #define MAXR 10000000ll using namespace std; typedef long long ll; int n,h,t; int p[MAXN],l[MAXN],r[MAXN]; void init(vector<int> val0,vector<int> a,vector<int> b,vector<int> m){ /*val0.resize(3); a.resize(3); b.resize(3); m.resize(3); for(int i=0;i<3;i++)SF("%d",&val0[i]); for(int i=0;i<3;i++)SF("%d",&a[i]); for(int i=0;i<3;i++)SF("%d",&b[i]); for(int i=0;i<3;i++)SF("%d",&m[i]);*/
p[0]=val0[0]; for(int i=1;i<n;i++) p[i]=(1ll*a[0]*p[i-1]+b[0])%m[0]; l[0]=val0[1]; r[0]=val0[2]; for(int i=1;i<h;i++){ l[i]=min(1ll*n-1,(1ll*a[1]*l[i-1]+b[1])%m[1]); int dist=r[i-1]-l[i-1]; r[i]=min(1ll*n-1,l[i]+(1ll*a[2]*dist+b[2])%m[2]); } } vector<int> v[MAXN]; int pre[MAXN]; ll calc
(int x){ ll res=1ll*x*t; ll sum=x; int far=-1; memset(pre,0,sizeof pre); for(int i=0;i<n;i++){ sum+=pre[i]; for(int j=0;j<int(v[i].size());j++) far=max(far,v[i][j]); ll add=max(0ll,p[i]-sum); if(add!=0&&far<i) return INF; sum+=add; res+=add; pre[far+1]-=add; } return res; } class SettingShield{ public: ll getOptimalCost(int n1,int h1,int t1,vector<int> val0,vector<int> a,vector<int> b,vector<int> m){ n=n1; h=h1; t=t1; //SF("%d%d%d",&n,&h,&t); init(val0,a,b,m); for(int i=0;i<h;i++) v[l[i]].push_back(r[i]); /*for(int i=0;i<n;i++) PF("%d ",p[i]); for(int i=0;i<h;i++) PF("\n%d %d",l[i],r[i]);*/ ll lx=0,rx=MAXR,ans=MAXR; while(lx<=rx){ ll midl=lx+(rx-lx)/3; ll midr=rx-(rx-lx)/3; ll v1=calc(midl),v2=calc(midr); //PF("<%lld %lld %lld:%lld %lld:%lld>\n",lx,rx,midl,v1,midr,v2); if(v1==INF||v1>v2){ lx=midl+1; ans=midr; } else{ rx=midr-1; ans=midl; } } return calc(ans); } };