[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 } 
View Code

 

posted @ 2022-06-05 09:24  PYWBKTDA  阅读(255)  评论(1编辑  收藏  举报