CF883D Packmen Strike Back

题目

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
*/



posted @ 2021-10-28 21:33  __Anchor  阅读(70)  评论(0编辑  收藏  举报