zoukankan      html  css  js  c++  java
  • CF883D Packmen Strike Back

    CF883D Packmen Strike Back

    (problem:)

    给出一个长度为N的序列,序列上每个位置或者是豆,或者是吃豆人,或者什么都没有
    现在要求给每个吃豆人定向(向左吃或向右吃),定向后吃豆人会一直朝这个方向走直到尽头并吃掉沿途的所有豆
    现在要求在保证尽量多的豆被吃的情况下,最小化达到这个数量所需要的时间(不一定走到尽头)

    (data) (range:)

    (N<=10^6)

    (solution:)

    此题也很妙啊
    考虑如果只有一个人,那么他要么往左要么往右,判断下就行了
    如果有至少两个人,那么所有豆子都可以被吃完,问题变为如何求吃完所有豆子所需要的最少时间
    这个时间本身并不好求
    容易发现答案具有单调性,于是我们考虑二分答案+验证
    如何验证呢?
    (f_i)表示从左往右前第i个人能够吃到的最靠右的豆子的位置(注意中间不能遗漏)
    那么考虑转移,有三种

    • 第i个人向右走
    • 第i个人向左走
    • 第i个人向左走,第i-1个人向右走

    分类讨论即可

    (space) (time) (complexity)

    (time:O(n))
    (space:O(n))

    (code:)

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N=1e6+5;
    int n,s[N],f[N];
    char ch[N];
    vector<int>p;
    inline bool ok(int l,int r){return l>r?1:(s[r]-s[l-1]==0);}
    inline int sum(int l,int r){return l>r?0:s[r]-s[l-1];}
    inline bool ck(int x)
    {
    	fill(f,f+n+1,0);
    	for(int i=1;i<=p.size();++i)
    	{
    		int pos=p[i-1];
    		if(ok(f[i-1]+1,pos-1))f[i]=max(f[i],pos+x);//第i个人向右走
    		if(ok(f[i-1]+1,pos-x-1))f[i]=max(f[i],pos);//第i个人向左走
    		if(i>1)
    			if(ok(f[i-2]+1,pos-x-1))f[i]=max(f[i],max(p[i-2]+x,pos));//第i个人向左走,第i-1个人向右走
    	}
    	return ok(f[p.size()]+1,n);
    }
    int main()
    {
    	scanf("%d",&n);
    	scanf("%s",ch+1);
    	for(int i=1;i<=n;++i)
    	{
    		s[i]=s[i-1];
    		if(ch[i]=='P')p.pb(i);
    		else if(ch[i]=='*')++s[i];
    	}
    	if(p.size()==1)
    	{
    		int pos=p[p.size()-1];
    		int suml=sum(1,pos-1),sumr=sum(pos+1,n);
    		if(!suml&&!sumr)return puts("0 0"),0;
    		int l=1;while(ok(1,l))++l;
    		int r=n;while(ok(r,n))--r;
    		if(l>pos)return printf("%d %d",sumr,r-pos),0;
    		if(r<pos)return printf("%d %d",suml,pos-l),0;
    		if(suml==sumr)printf("%d %d",suml,min(pos-l,r-pos));
    		else printf("%d %d",max(suml,sumr),suml>sumr?pos-l:r-pos);
    	}
    	else
    	{
    		int l=0,r=n;
    		while(l+1<r)
    		{
    			int mid=l+r>>1;
    			ck(mid)?r=mid:l=mid;
    		}
    		printf("%d %d
    ",sum(1,n),r);
    	}
    	return 0;
    }
    
  • 相关阅读:
    poj1904 King's Quest
    ACM竞赛须掌握的知识 以及 2个版本的POJ推荐 @ NKOJ discuss 转载的
    poj1466
    C++23中设计模式的factory模式
    poj3667 hotel
    poj1505 Copying Books
    在linux系统中安装VSCode(Visual Studio Code)
    Spring_的jar详细说明
    java开发问题总结4Maven使用问题汇总
    线程同步之信号量(sem_init,sem_post,sem_wait)
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/13741971.html
Copyright © 2011-2022 走看看