E. Packmen(贪心+二分[注意细节])

    技术2026-01-05  13

    这题虽然想到了贪心+二分,但是模拟细节wa到怀疑人生…

    因 为 考 虑 每 个 p 有 两 种 走 法 , 向 左 走 再 向 右 走 因为考虑每个p有两种走法,向左走再向右走 p,

    或 者 向 右 走 再 向 左 走 或者向右走再向左走

    那 么 我 们 先 考 虑 第 一 个 p 那么我们先考虑第一个p p

    这 个 p 左 边 的 所 有 ∗ 都 被 吃 掉 , 设 走 到 最 左 边 的 ∗ 距 离 是 l 这个p左边的所有*都被吃掉,设走到最左边的*距离是l p,l

    然 后 右 边 也 会 有 部 分 ∗ 被 吃 掉 , 设 走 到 最 右 边 的 ∗ 是 r 然后右边也会有部分*被吃掉,设走到最右边的*是r ,r

    所 以 就 是 需 要 走 m i n ( l , r ) ∗ 2 + m a x ( l , r ) 所以就是需要走min(l,r)*2+max(l,r) min(l,r)2+max(l,r)

    然 后 记 录 一 下 这 个 p 走 到 最 右 边 的 点 r 然后记录一下这个p走到最右边的点r pr

    下 一 个 p 需 要 把 r 到 自 己 间 的 ∗ 都 吃 掉 下一个p需要把r到自己间的*都吃掉 pr

    #include <bits/stdc++.h> using namespace std; const int maxn=2e5+10; #define f first #define s second typedef pair<int,int>p; int n,top,Left,in[maxn],sumn; char a[maxn]; bool isok(int mid) { int l=Left,temp=0;//l表示当前没有被吃掉的最左边的* for(int i=1;i<=top;i++) { int index=in[i],q=in[i];//当前p的位置是index for(int j=index-1;j>=l;j--)//首先把[l,index-1]所有*吃掉 { if(a[j]!='*') continue; if(index-j>mid) return false; q=j,temp++;//消掉星星 } l=index+1; for(int j=index+1;j<=n;j++)//现在就尽可能多吃[index+1,n]的* { if(a[j]=='P') break;//留给下一个p去处理吧,下一个p吃的更远 if(a[j]=='.') continue; int now=j-index;//假设这个now是吃掉的最右边的点 if(min(now,index-q)*2+max(now,index-q)<=mid) temp++,l=j+1; else break; } } if(temp==sumn) return true; else return false; } int main() { cin >> n >> (a+1); for(int i=1;i<=n;i++) { if(a[i]=='*') { sumn++; if(Left==0) Left=i; } else if(a[i]=='P') in[++top]=i; } int l=1,r=n*2,mid,ans; while(r>=l) { mid =l+r>>1; if( isok(mid) ) r=mid-1,ans=mid; else l=mid+1; } cout<<ans; }

    另一份贪心+二分

    思 路 来 源 于 思路来源于 点我呀

    #include <bits/stdc++.h> using namespace std; int n; char s[200009]; bool isok(int mid) { int pos=-1,last=-1;//pos记录*的位置,last是当前覆盖到的最远点 for(int i=1;i<=n;i++) { if(i>last&&s[i]=='*'&&pos==-1) pos=i;//遇到没有标记的* if(s[i]=='P') { if(pos==-1)//前面没有*,直接往右走 last=i+mid; else { int x = i-pos;//求出去左边的距离 if( x>mid ) return false;//到不了 if( x*3<mid )//先左边再右边可以往右走得更远 last=i+mid-2*x; else //先右边再左边 last=(mid-x)/2+i; } pos=-1; } } if(pos==-1) return true; return false; } int main() { cin >> n >> (s+1); int l=1,r=n*2,ans=-1; while(r>=l) { int mid = (l+r)/2; if( isok(mid) ) r=mid-1,ans=mid; else l=mid+1; } cout<<ans; }
    Processed: 0.015, SQL: 9