CF883D Packmen Strike Back
题目
分析
没看懂题意题。
注意,这里说的结束是可以在任意时间结束,即最优显然是在吃到最后一个的时候结束。(直接导致我做法假了)
回到原题。
首先题目很显然是只要有两个人就能全部拿到,所以我们特判一下只有一个人的情况就行了。
然后我们发现这个最短时间显然可以二分,于是就直接二分一下,考虑怎么检验。(这里是这道题二分最大的妙处)
发现每一个人我们可以贪心地都走 \(mid\) 的时间,那么问题变成了一堆线段的覆盖问题,这个我们有个经典做法就是直接dp。
设 \(dp[i]\) 表示前 \(i\) 个人最右可以到达的点,使得 \([1,dp[i]]\) 的豆子全部都被吃掉。
那么 \(dp\) 的转移就是分成三种情况讨论:
第一种,\(dp[i-1]\) 到 \(pos[i]\) 没有豆子,我们可以让这个人直接往右走。
第二种,这个范围内有豆子,于是可以让这个人往左走吃掉。
第三种,第 \(i\) 个人往左走,第 \(i-1\) 个人往右走,要求中间不能有豆子,否则不能转移。
最后判断最后一个是否可以到达 \(n\) 即可。
代码
#include<bits/stdc++.h>
using namespace std;
//#ifdef ONLINE_JUDGE
// #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
// char buf[1<<21],*p1=buf,*p2=buf;
//#endif
template<typename T>
inline void read(T &x){
x=0;bool f=false;char ch=getchar();
while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template<typename T>
inline void write(T x){
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
#define ll long long
#define ull unsigned long long
#define ld long double
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define pc putchar
#define PII pair<int,int>
#define rep(i,x,y) for(register int i=(x);i<=(y);i++)
#define dep(i,y,x) for(register int i=(y);i>=(x);i--)
const int MOD=1e9+7;
inline int inc(int x,int y){x+=y;return x>=MOD?x-MOD:x;}
inline int dec(int x,int y){x-=y;return x<0?x+MOD:x;}
inline void incc(int &x,int y){x+=y;if(x>=MOD) x-=MOD;}
inline void decc(int &x,int y){x-=y;if(x<0) x+=MOD;}
inline void chkmin(int &x,int y){if(y<x) x=y;}
inline void chkmax(int &x,int y){if(y>x) x=y;}
const int N=1e6+5,M=1e6+5,INF=1e9+7;
int n,sta[N],top,num,dp[N],pre[N],Max1,Max2,Ans=INF,L,R;
char str[N];
inline bool Check(int tim){
memset(dp,0,sizeof(dp));
for(int i=1;i<=top;i++){
if(dp[i-1]>=sta[i]-1||pre[dp[i-1]]==pre[sta[i]-1]) dp[i]=max(dp[i],sta[i]+tim);
if(dp[i-1]>=sta[i]-tim-1||pre[dp[i-1]]==pre[sta[i]-tim-1])dp[i]=max(dp[i],sta[i]);
if(i>1&&(dp[i-2]>=sta[i]-tim+1||pre[dp[i-2]]==pre[sta[i]-tim-1])) dp[i]=max(dp[i],sta[i-1]+tim);
dp[i]=min(dp[i],n); //p[i]+k可能超过n,防止下标越界。
}
return pre[dp[top]]==pre[n];
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(false);
// double ST=clock();
read(n);
scanf("%s",str+1);L=R=-1;
rep(i,1,n){
pre[i]=pre[i-1];
if(str[i]=='P') sta[++top]=i;
else if(str[i]=='*') pre[i]++;
if(L==-1&&str[i]=='*') L=i;
if(str[i]=='*') R=i;
}
num=pre[n];
if(top>1){
write(num),pc(' ');
int l=0,r=1e6;
while(l<=r){
int mid=l+r>>1;
if(Check(mid)) r=mid-1,Ans=mid;
else l=mid+1;
}
write(Ans);
}
else{
int num1=0,num2=0;
rep(i,1,sta[1]) if(str[i]=='*') num1++;
rep(i,sta[1],n) if(str[i]=='*') num2++;
if(num1==num2) write(num1),pc(' '),write(min(R-sta[1],sta[1]-L));
else if(num1>num2) write(num1),pc(' '),write(sta[1]-L);
else write(num2),pc(' '),write(R-sta[1]);
}
//#ifndef ONLINE_JUDGE
// cerr<<"\nTime:"<<(clock()-ST)/CLOCKS_PER_SEC<<"s\n";
//#endif
return 0;
}
/*
4
1 2
2 3
3 3
4 3
*/