zoukankan      html  css  js  c++  java
  • 1596:动物园

    1596:动物园

    时间限制: 1000 ms 内存限制: 524288 KB
    提交数: 261 通过数: 146
    【题目描述】

    原题来自:APIO 2007

    新建的圆形动物园是亚太地区的骄傲。圆形动物园坐落于太平洋的一个小岛上,包含一大圈围栏,每个围栏里有一种动物。如下图所示:

    你是动物园的公关主管。你要做的是,让每个参观动物园的游客都尽可能高兴。今天有一群小朋友来到动物园参观,你希望能让他们在动物园度过一段美好的时光。但这并不是一件容易的事——有些小朋友喜欢某些动物,而有些小朋友则害怕某些动物。例如, Alex 喜欢可爱的猴子和考拉,而害怕拥有锋利牙齿的狮子。而 Polly 会因狮子有美丽的鬃毛而喜欢它,但害怕有臭味的考拉。

    你可以选择将一些动物从围栏中移走以使得小朋友不会害怕。但你移走的动物也不能太多,否则留给小朋友们观赏的动物就所剩无几了。

    每个小朋友站在大围栏圈的外面,可以看到连续的 5个围栏。你得到了所有小朋友喜欢和害怕的动物信息。当下面两处情况之一发生时,小朋友就会高兴:

    1、至少有一个他害怕的动物被移走;

    2、至少有一个他喜欢的动物没被移走。

    例如,考虑下图中的小朋友和动物:

    假如你将围栏 4和 12 的动物移走。Alex 和 Ka-Shu 将很高兴,因为至少有一个他们害怕的动物被移走了。这也会使 Chaitanya 高兴,因为他喜欢的围栏 6 和 8

    中的动物都保留了。但是,Polly 和 Hwan 将不高兴,因为他们看不到任何他们喜欢的动物,而他们害怕的动物都还在。这种安排方式使得三个小朋友高兴。

    现在换一种方法,如果你将围栏 4和 6 中的动物移走,Alex 和 Polly 将很高兴,因为他们害怕的动物被移走了。Chaitanya 也会高兴,虽然他喜欢的动物 6 被移走了,他仍可以看到围栏 8 里面他喜欢的动物。同样的 Hwan 也会因可以看到自己喜欢的动物 12
    而高兴。唯一不高兴的只有 Ka-Shu。

    如果你只移走围栏 13
    中的动物,Ka-Shu 将高兴,因为有一个他害怕的动物被移走了,Alex, Polly, Chaitanya 和 Hwan 也会高兴,因为他们都可以看到至少一个他们喜欢的动物。所以有 5个小朋友会高兴。这种方法使得了最多的小朋友高兴。

    【输入】

    输入的第一行包含两个整数 N,C,用空格分隔。N 是围栏数,C 是小朋友的个数。围栏按照顺时针的方向编号为 1,2,3,…,N。

    接下来的 C行,每行描述一个小朋友的信息,以下面的形式给出:E F L X1 X2 ⋯ X F Y1 Y2 ⋯ YL。

    其中E
    表示这个小朋友可以看到的第一个围栏的编号,换句话说,该小朋友可以看到的围栏为 E,E+1,E+2,E+3,E+4。注意,如果编号超过 N 将继续从 1 开始算。如:当 N=14,E=13 时,这个小朋友可以看到的围栏为 13,14,1,2 和 3。

    F表示该小朋友害怕的动物数。L表示该小朋友喜欢的动物数。

    围栏 X1,X2,⋯,XF中包含该小朋友害怕的动物。围栏 Y1,Y2,⋯,YL中包含该小朋友喜欢的动物。

    X1,X2,⋯,XF,Y1,Y2,⋯,YL是两两不同的整数,而且所表示的围栏都是该小朋友可以看到的。

    【输出】

    仅输出一个数,表示最多可以让多少个小朋友高兴。小朋友已经按照他们可以看到的第一个围栏的编号从小到大的顺序排好了(这样最小的E对应的小朋友排在第一个,最大的 E对应的小朋友排在最后一个)。

    注意可能有多于一个小朋友对应的 E是相同的。

    【输入样例】

    14 5
    2 1 2 4 2 6
    3 1 1 6 4
    6 1 2 9 6 8
    8 1 1 9 12
    12 3 0 12 13 2

    【输出样例】

    5

    【提示】

    样例说明 1

    样例 1给出了前面描述的示例情形。它使得所有小朋友(C=5)高兴。

    样例输入 2

    12 7
    1 1 1 1 5
    5 1 1 5 7
    5 0 3 5 7 9
    7 1 1 7 9
    9 1 1 9 11
    9 3 0 9 11 1
    11 1 1 11 1

    样例输出 2

    6

    样例说明 2

    样例 2给出了这样的情形,要使得所有小朋友(C=7)都高兴是不可能的。

    数据范围与提示:

    对于每一个测试点,如果你的答案正确,则该测试点得满分,否则得 0分。

    对于全部数据,10≤N≤104,1≤C≤5×104,1≤E≤N。

    【来源】

    思路:
    难~~
    发现数据范围都很大,只有唯一一个5可以表示状态,所以设置状态f[i][j]为第i个位置的状态是j时的最多满足人数,j表示以i结尾的状态.
    (j&15)<<1表示x x x x 0 //最后一个位置不放
    (j&15)<<1|1表示x x x x 1//最后一个位置放
    转移:f[j][k]=max(f[j-1][(k&15)<<1],f[j-1][(k&15)<<1|1])+num[j][k];

    注意因为是环形分布,所以对于i=0和i=n的方案数应该是相同的,所以预处理出对于每一个i=0的状态(代码里有提到)

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-');
            ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48);
            ch=getchar();
        }
        return (f)?(-s):(s);
    }
    //#define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');
            return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    /*
    inline void writeln(ll x)
    {
        write(x);
        putchar('
    ');
        return;
    }*/
    int f[10005][35],inf=0x3f3f3f3f;
    int n,c,num[10005][35];
    
    int main()
    {
    	n=read();
    	c=read();
    	for(int i=1;i<=c;i++)
    	{
    		int happy=0,unhappy=0,e,f,l;
    		e=read(),f=read(),l=read();
    		for(int j=1;j<=f;j++)
    		{
    			int x=read();
    			happy|=(1<<(x-e+n)%n);
    		}
    		
    		for(int j=1;j<=l;j++)
    		{
    			int x=read();
    			unhappy|=(1<<(x-e+n)%n);
    		}
    		
    		for(int j=0;j<32;j++)//最多有32种情况
    		{
    			num[e][j]/*第e个围栏,以j为状态数可以满足的最多的人数*/
    			+=(((j^31)&happy)||(j&unhappy))?1:0;
    		 } 
    		
    	}
    	
    	int ans=0;
    	for(int i=0;i<32;i++)//第0个人的状态和第n个人的状态应该是相同de,
    	//所以我们在这里还需要一层循环来枚举第0个人的状态,初始化其为0 
    	{
    		memset(f,-0x3f,sizeof(f));
    		f[0][i]=0; 
    		for(int j=1;j<=n;j++)
    			for(int k=0;k<32;k++)
    			{
    				f[j][k]=max(f[j-1][(k&15)<<1],f[j-1][(k&15)<<1|1])+num[j][k];
    			}
    			
    		ans=max(ans,f[n][i]);
    	}
    	
    	cout<<ans<<'
    ';
    	return 0;
    }
    

    ✿✿ヽ(°▽°)ノ✿

  • 相关阅读:
    MySQL中的内置系统函数
    Mysql导出表结构及表数据 mysqldump用法
    MySQL事务处理案例演示
    mysql中int、bigint、smallint 和 tinyint的区别详细介绍
    mysql 获取上个月,这个月的第一天或最后一天
    ★MySQL一些很重要的SQL语句
    remix的使用
    nodejs部署智能合约的方法-web3 0.20版本
    js同步-异步-回调
    ganache与metamask
  • 原文地址:https://www.cnblogs.com/yxr001002/p/14431094.html
Copyright © 2011-2022 走看看