[hdu6757]Hunting Monsters
关于打怪兽的顺序,有经典结论:
优先打$a<b$的怪兽,这些怪兽按$a$从小到大,其余怪兽按$b$从大到小
(证明调整法即可,具体略)
将所有怪兽以此法排序,则打怪兽的顺序总是从前往后
对于$a<b$的怪兽,当确定答案后,总是贪心打一个前缀
同时,显然答案单调不降,因此前缀长度也单调不降
对于$a\ge b$的怪兽,定义$f_{i,j}$表示$[i,n]$中打$j$只怪兽的最小体力,转移即
$$
f_{i,j}=\min(f_{i+1,j},\min(f_{i+1,j-1}-b_{i},0)+a_{i})
$$
若$(f_{i+1,j-1}\le )f_{i+1,j}\le b_{i}(\le a_{i})$,根据递推式,显然$f_{i,j}=f_{i+1,j}\le b_{i}$
求出最小的$j$满足$f_{i+1,j}\le b_{i}$,则$[0,j]$中均不变$,\{b_{i}\}\cup (j,n]$即对前一项$+(a_{i}-b_{i})$取$\max$
归纳$\{b_{i}\}\cup (j,n]$上凸,则上述操作即在斜率中加入$a_{i}-b_{i}$并重新排序
另外,对其的操作即增加$b_{i}$和删除第二个元素起比$b_{i}$小的元素,显然均保持凸性
根据凸性,使用优先队列维护斜率,合并时根据前者决策单调性分治即可
时间复杂度为$o(n\log n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 300005 4 #define mod 1000000007 5 #define ll long long 6 #define pii pair<int,int> 7 #define fi first 8 #define se second 9 int t,n,na,nb,ans,x[N],y[N];ll sum[N],fa[N],fb[N],f[N]; 10 pii a[N],b[N];priority_queue<ll>q; 11 void solve(int l,int r,int x,int y){ 12 if (l>r)return; 13 int mid=(l+r>>1); 14 for(int i=x;i<=y;i++) 15 if ((i<=mid)&&(mid-i<=nb))f[mid]=min(f[mid],max(fa[i],fb[mid-i]-sum[i])); 16 for(int i=x;i<=y;i++) 17 if ((i<=mid)&&(mid-i<=nb)&&(f[mid]==max(fa[i],fb[mid-i]-sum[i]))){ 18 solve(l,mid-1,x,i),solve(mid+1,r,i,y); 19 return; 20 } 21 } 22 int main(){ 23 scanf("%d",&t); 24 while (t--){ 25 scanf("%d",&n),na=nb=0; 26 for(int i=1;i<=n;i++)scanf("%d",&x[i]); 27 for(int i=1;i<=n;i++)scanf("%d",&y[i]); 28 for(int i=1;i<=n;i++){ 29 if (x[i]<y[i])a[++na]=make_pair(x[i],y[i]); 30 else b[++nb]=make_pair(-y[i],x[i]); 31 } 32 sort(a+1,a+na+1),sort(b+1,b+nb+1); 33 for(int i=1;i<=nb;i++)b[i]=make_pair(b[i].se,-b[i].fi); 34 for(int i=1;i<=na;i++){ 35 sum[i]=sum[i-1]+(a[i].se-a[i].fi); 36 fa[i]=max(fa[i-1],a[i].fi-sum[i-1]); 37 } 38 for(int i=nb,j=0;i;i--){ 39 ll now=b[i].se; 40 if (!q.empty()){ 41 ll s=q.top(); 42 q.pop(),q.push(s-b[i+1].se+b[i].se); 43 } 44 while ((!q.empty())&&(now-q.top()<=b[i].se))now-=q.top(),fb[++j]=now,q.pop(); 45 if (!q.empty())now-=q.top(),q.pop(),q.push(b[i].se-now); 46 q.push(b[i].se-b[i].fi); 47 if (i==1){ 48 ll now=b[i].se; 49 while (!q.empty())now-=q.top(),fb[++j]=now,q.pop(); 50 } 51 } 52 memset(f,0x3f,sizeof(f)); 53 ans=0,solve(0,n,0,na); 54 for(int i=1;i<=n;i++)ans=(ans+f[i]%mod*i)%mod; 55 printf("%d\n",ans); 56 } 57 return 0; 58 }