zoukankan      html  css  js  c++  java
  • 2019.9.1 动物园

    题目描述

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

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

    你可以选择将一些动物从围栏中移走以使得小朋友不会害怕。但你不能移走所有的动物,否则小朋友们就没有动物可看了。

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

    • 至少有一个他害怕的动物被移走

    • 至少有一个他喜欢的动物没被移走

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

    假如你将围栏 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 是围栏数(1≤N≤10 000),C是小朋友的个数(1≤C≤50 000)。围栏按照顺时针的方向编号为 1,2,3,…,N。

    接下来的 C 行,每行描述一个小朋友,描述下面的形式给出:

    E F L X1 X2 … XF Y1 Y2 … YL

    其中:

    E 表示小朋友可以看到的第一个围栏的编号(1≤E≤N),也就是说,小朋友可以看到的围栏为 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 是相同的。

    输出格式

    仅输出一个数,表示最多可以让多少个小朋友高兴。

    输入输出样例

    输入 #1
    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 
    输出 #1
    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 
    11 1 1 1 11 1
     
    输出 #2
    6

    说明/提示

    第一个样例是题目描述中的例子,所有的 C=5 个小朋友都能高兴。第二个样

    例是一个不能使得所有 C=7 个小朋友都高兴的例子。

    题源洛谷3622/APIO2007


    看到一个小朋友只能看到五个 考虑状压dp
    用dp[i][j]表示前i个围栏中最后五个的状态是j
    所以我们每次枚举第2-6个的状态
     
    假设用num[i][j]表示以i开头的五个围栏状态是j时能使多少个e=i的小朋友高兴
    num可以初始化
    所以dp[i][j]=max(dp[i-1][(j&15)<<1],dp[i-1][(j&15)<<1|1])+num[i][j];
    同时注意要处理环 在计算dp[1]时每次固定下第一个及最后四个的状态
    其余置为-inf即可
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int n,c,dp[100050][(2<<6)+1],num[100050][(2<<6)+1],ans;
    int main()
    {
        scanf("%d%d",&n,&c);
        for(int i=1;i<=c;i++)
        {
            int e,f,l;
            scanf("%d%d%d",&e,&f,&l);
            int x,s1=0,s2=0;
            for(int j=1;j<=f;j++)
            {
                scanf("%d",&x);
                x=(x-e+n)%n;
                s1|=(1<<x);
            }
            for(int j=1;j<=l;j++)
            {
                scanf("%d",&x);
                x=(x-e+n)%n;
                s2|=(1<<x);
            }
            for(int s=0;s<32;s++)
                if((s1&(~s))||(s2&s))++num[e][s];
        }
        for(int s=0;s<32;s++)
        {
            memset(dp[0],128,sizeof dp[0]);
            dp[0][s]=0;
            for(int i=1;i<=n;i++)
                for(int statu=0;statu<32;statu++)
                    dp[i][statu]=max(dp[i-1][(statu&15)<<1],dp[i-1][(statu&15)<<1|1])+num[i][statu];
            ans=max(ans,dp[n][s]);
        }
        printf("%d",ans);
        return 0;
    }
    /*====年轻人,瞎搞是出不了省一的,这就是现实====*/
  • 相关阅读:
    1009 说反话 (20)
    1008 数组元素循环右移问题 (20)
    1007 素数对猜想(20 分)
    1006 换个格式输出整数 (15)
    PAT 1005 继续(3n+1)猜想 (25)
    PAT 1004 成绩排名 (20)
    PAT 1003 我要通过!(20)
    PAT 1002 写出这个数 (20)(20 分)
    PAT 1001 害死人不偿命的(3n+1)猜想 (15)
    人口普查(20) PAT
  • 原文地址:https://www.cnblogs.com/qxds/p/11460500.html
Copyright © 2011-2022 走看看