• 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<<"
    Time:"<<(clock()-ST)/CLOCKS_PER_SEC<<"s
    ";
    //#endif
    	return 0;
    }
    /*
    4
    1 2
    2 3
    3 3
    4 3
    */
    
    
    
    
  • 相关阅读:
    关于浮动清除的一些小感悟,4种方法清除浮动
    6号css学习小记
    pexpect-pxssh-登陆Linux-执行命令
    chroot命令
    Loadrunner11点击录制脚本无响应,IE页面弹不出——解决方案汇总
    JAVA实验五(网络编程)
    Java实验三
    JAVA实验二(面向对象)
    JAVA实验一
    Tfs链接错误解决方案
  • 原文地址:https://www.cnblogs.com/Akmaey/p/15477858.html
Copyright © 2020-2023  润新知