动物园 \([APIO \ 2007]\)

· 题意:

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

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

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

每个小朋友站在大围栏圈的外面,可以看到连续的

个围栏。你得到了所有小朋友喜欢和害怕的动物信息。当下面两处情况之一发生时,小朋友就会高兴:

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

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

假如你将围栏 \(4\) 和 \(12\) 的动物移走。Alex 和 Ka-Shu 将很高兴,因为至少有一个他们害怕的动物被移走了。这也会使 Chaitanya 高兴,因为他喜欢的围栏 \(6\) 和 \(8\)中的动物都保留了。但是,Polly 和 Hwan 将不高兴,因为他们看不到任何他们喜欢的动物,而他们害怕的动物都还在。这种安排方式使得三个小朋友高兴。

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

而高兴。唯一不高兴的只有 Ka-Shu。

如果你只移走围栏 \(13\)

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

你要求出:最多可以满足的小朋友的数量。

·数据范围

$N \leq 10^4 , C \leq 5 \times 10 ^ 4 $

·输入格式

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

接下来的 \(C\)行,每行描述一个小朋友的信息,以下面的形式给出:

\(E,F,L,X_1,\dots X_n , Y_1,\dots,Y_n\)。

其中: \(E\) 表示这个小朋友可以看到的第一个围栏的编号,换句话说,该小朋友可以看到的围栏为 \(E_1 \dots E_5\) 。注意,如果编号超过 $ n $ 将继续从 $ 1 $ 开始算。

\(F\) 表示该小朋友害怕的动物数。

\(L\) 表示该小朋友喜欢的动物数。

围栏 \(X_i\)中包含该小朋友害怕的动物。围栏 \(Y_i\)中包含该小朋友喜欢的动物。

$X_i , Y_i $ 是两两不同的整数,而且所表示的围栏都是该小朋友可以看到的。

小朋友已经按照他们可以看到的第一个围栏的编号从小到大的顺序排好了(这样最小的 \(E\) 对应的小朋友排在第一个,最大的 \(E\) 对应的小朋友排在最后一个)。

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

·输出格式

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


·题解

· \(DP\)

这个题 \(GS\) 就 \(GS\) 在环上了。

如果以小朋友为基准进行 \(DP\) , 由于其并不连续,所以你并没有方法处理环。(其实这里的不可以,意思是 \(T\) )

那么就想一个能处理环还不 \(T\) 的算法。

那你的 \(DP\) 数组肯定是要开两维,那上面那种情况已经被否决了。

那么你可以这么定义这个 \(DP\) :

\(DP_{ i , j }\) : $ i $ 表示目前枚举到第 \(i\) 个栅栏, 其后面的,包括其自身的 \(5\) 个数的状态压缩一下成为 \(j\) .

那么先挂一下方程:

\[dp_{ i , j } = \max \{ dp_{ i - 1 , ( ( ( 1 << 4 ) - 1 ) \& j ) << 1 } , dp_{ i - 1 , ( ( ( 1 << 4 ) - 1 ) \& j ) << 1 | 1 } \} + b_{ i , j }
\]

这个 $ b_{ i , j } $ 的意思是, 在从 \(i\) 开始 , \(j\) 为状态下, 可以让多少个小朋友高兴。存在之的充分必要条件是此点上有小朋友的观察。

那么这个 一堆的下标是表示什么的呢?

显然,$ 2 ^ 4 - 1 $ 是 \(\left(1111\right)_2\) 你拿目前的状态 \(\&\) 这个 , 相当于未保存第五位的数,即你因为 \(i\) 比 \(i-1\) 多 \(1\) 而末位多出的一位。

你现在左移一位,那么就使 \(j\) 的第四位,变成了最高位。

其实仔细的想一想,其实很有道理。你 从 $ i $ 从左往右数的第 $ 4 $ 个,不就是 $ i - 1 $ 从左往右选的第 $ 5 $ 个数。

在最低位 $ 0 $ $| \ 1 $ , 就是 $ i - 1 $ 是 $ 1 $ , 不动就是 $ 0 $ .

在原来状态得到的最大值,加上此位置小盆友的快乐数,即此状态下的最大答案。


子问题 \(1\) :如何预处理 \(b\) 数组

因为只有当 $ i $ 上有小朋友的观察时才有 \(b\) 的值 .

那么就好说了,在输入小朋友时,你用两个变量;

喜欢的,用 \(love\) 或起来;害怕的也是,用 $ fear $ 。

枚举一遍状态 $ j $ , 当:

$ j 按位与 love $ 为真 或 $ ( $ $ \ j取反 \ 按位与 \ fear )$ 为真,即可累计答案。

(这个地方好想一些,挺巧妙的)。


子问题 \(2\) : 如何处理环

考虑什么情况下可以使答案合法:

\(n\) 的状态的后四位和 \(1\) 的状态的前四位相同时。

那么如何处理得到这种情况呢?

我们可以定义一个 \(n\) 的镜像点 , 视为 \(dp_{ 0 , j }\) 。 表示第 \(n\) 个点 \(j\) 状态 。

使从此点开始 \(DP\) ,那么使其他的 \(dp_{ 0 , k } ( k \in A = \{ 1, \dots , 31 | k \ne j \} )\)

均为负无穷,此时对于后面的加减,可以抵消其作用。

最后输出 \(dp_{ n , j }\) 的最大值即可。

· \(code\)

有些东西没有用,可以恰当的删一下。

点击查看代码
#include<bits/stdc++.h>
const int C = 5e4 + 100 ;
const int N = 1e4 + 100 ;
const int State = ( 1 << 5 ) - 1 ;
using namespace std ;
int n , m ;
class node
{
public:
int left , right ;
int num_fond , num_afraid ;
int fondations[ 10 ] , afraid[ 10 ] ;
} a[ C ] ;
int dp[ N ][ State + 1 ] ;
int b[ N ][ State + 1 ] ;
int papa = 0 , aiai = 0 ;
signed main ( )
{
ios::sync_with_stdio( 0 ) ;
cin.tie( 0 ) ; cout.tie( 0 ) ;
cin >> n >> m ;
for ( int i = 1 ; i <= m ; ++ i )
{
cin >> a[ i ].left ;
papa = 0 ; aiai = 0 ;
cin >> a[ i ].num_afraid >> a[ i ].num_fond ;
for ( int j = 1 ; j <= a[ i ].num_afraid ; ++ j )
{
cin >> a[ i ].afraid[ j ] ;
int pp = ( a[ i ].afraid[ j ] - a[ i ].left + n ) % n ;
papa |= ( 1 << pp ) ;
}
for ( int j = 1 ; j <= a[ i ].num_fond ; ++ j )
{
cin >> a[ i ].fondations[ j ] ;
int pp = ( a[ i ].fondations[ j ] - a[ i ].left + n ) % n ;
aiai |= ( 1 << pp ) ;
}
for ( int j = 0 ; j <= State ; ++ j )
{
if( ( j & papa ) || ( ( ~ j ) & aiai ) )
{
b[ a[ i ].left ][ j ] ++ ;
}
}
}
int ans = -114514 ;
for ( int kala = 0 ; kala <= State ; ++ kala )
{
memset( dp[ 0 ] , 128 , sizeof ( dp[ 0 ] ) ) ;
dp[ 0 ][ kala ] = 0 ;
for ( int i = 1 ; i <= n ; ++ i )
{
for ( int j = 0 ; j <= State ; ++ j )
{
dp[ i ][ j ] = max ( dp[ i - 1 ][ ( ( j & ( 15 ) ) << 1 ) ] , dp[ i - 1 ][ ( ( j & ( ( 15 ) ) ) << 1 | 1 ) ] ) + b[ i ][ j ] ;
}
}
ans = max( ans , dp[ n ][ kala ] ) ;
}
cout << ans ;
}

·结尾撒花 \(\color{pink}✿✿ヽ(°▽°)ノ✿\)

动物园 (APIO 2007) 状压DP的更多相关文章

  1. 2018.09.08 bzoj1151: [CTSC2007]动物园zoo(状压dp)

    传送门 状压dp好题啊. 可以发现这道题的状压只用压缩5位. f[i][j]表示当前在第i个位置状态为j的最优值. 显然可以由f[i-1]更新过来. 因此只用预处理在第i个位置状态为j时有多少个小朋友 ...

  2. 【[APIO/CTSC2007]动物园】状压DP

    题目测评:https://www.luogu.org/problemnew/show/P3622 题目描述 新建的圆形动物园是亚太地区的骄傲.圆形动物园坐落于太平洋的一个小岛上,包含一大圈围栏,每个围 ...

  3. bzoj1231[Usaco2008 Nov]mixup2 混乱的奶牛(状压dp)

    1231: [Usaco2008 Nov]mixup2 混乱的奶牛 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1032  Solved: 588[ ...

  4. 状压dp学习笔记(紫例题集)

    P3451旅游景点 Tourist Attractions 这个代码其实不算是正规题解的(因为我蒟蒻)是在我们的hzoj上内存限制324MIB情况下过掉的,而且经过研究感觉不太能用滚动数组,所以那这个 ...

  5. 简单状压dp的思考 - 最大独立集问题和最大团问题 - 贰

    接着上文 题目链接:最大独立集问题 上次说到,一种用状压DP解决任意无向图最大团问题(MCP)的方程是: 注:此处popcountmax代表按照二进制位下1的个数作为关键字比较,即选择二进制位下1的个 ...

  6. BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3336  Solved: 1936[Submit][ ...

  7. nefu1109 游戏争霸赛(状压dp)

    题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰 ...

  8. poj3311 TSP经典状压dp(Traveling Saleman Problem)

    题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...

  9. [NOIP2016]愤怒的小鸟 D2 T3 状压DP

    [NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...

  10. 【BZOJ2073】[POI2004]PRZ 状压DP

    [BZOJ2073][POI2004]PRZ Description 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍 ...

随机推荐

  1. arm linux 移植 SQLite 3

    背景 SQLite 是 一个 常用于 嵌入式平台的 轻量级数据库. host平台 :Ubuntu 16.04 arm平台 : S5P6818 SQLite :3.31.1 arm-gcc :4.8.1 ...

  2. C#语言编写的仅有8KB大小的简易贪吃蛇开源游戏

    前言 今天大姚给大家分享一款由C#语言编写的仅有8KB大小的简易贪吃蛇开源游戏:SeeSharpSnake. 项目特点 该仓库中的项目文件和脚本可以用多种不同的配置构建相同的游戏,每个配置生成的输出大 ...

  3. 哇塞,实测780MB/s!基于RK3568J与FPGA的PCIe通信案例详解

    ARM + FPGA架构有何种优势 近年来,随着中国新基建.中国制造2025的持续推进,单ARM处理器越来越难满足工业现场的功能要求,特别是能源电力.工业控制.智慧医疗等行业通常需要ARM + FPG ...

  4. spring cloud 上云的情况下,Ribbon 客户端负载均衡 与 ALB 服务端负载均衡的选择

    在云环境(例如AWS)中,由于云提供商通常提供强大的负载均衡服务(如AWS的ALB),一般不再需要使用Ribbon这种客户端负载均衡方案.云环境中的负载均衡器通常能够提供更高的可靠性.可扩展性和简化的 ...

  5. Eggjs 设置跨域请求 指定地址跨域 nodejs

    首先egg自身框架没有直接设置允许跨域请求的功能和接口,所以需要第三方包来设置跨域请求! 先安装第三方包来设置跨域,使用egg-cors // npm npm i egg-cors --save // ...

  6. Solo 开发者周刊 (第2期):一站式解决各类办公绘图问题

    这里会整合 Solo 社区每周推广内容.产品模块或活动投稿,每周五发布.在这期周刊中,我们将深入探讨开源软件产品的开发旅程,分享来自一线独立开发者的经验和见解.本杂志开源,欢迎投稿. 好文推荐 重新思 ...

  7. 数据仓库建模工具之一——Hive学习第二天

    Hive的概述 1.Hive基本概念 1.1 Hive简介 Hive本质是将SQL转换为MapReduce的任务进行运算,底层由HDFS来提供数据存储,说白了hive可以理解为一个将SQL转换为Map ...

  8. ModuleNotFoundError: No module named 'import_export'

    当你遇到 "ModuleNotFoundError: No module named 'import_export'" 错误时,这表示你的 Python 脚本或应用程序试图导入名为 ...

  9. C#从6.0~9.0都更新了什么?

    一.C#6中新增的功能 get 只读属性 简洁的语法来创建不可变类型,仅有get访问器: public string FirstName { get; } public string LastName ...

  10. 顺序表之单链表(C实现)

    // Code file created by C Code Develop #include "ccd.h"#include "stdio.h"#includ ...