传送门

Description

Kiana 最近沉迷于一款神奇的游戏无法自拔。

简单来说,这款游戏是在一个平面上进行的。

有一架弹弓位于 $(0,0)$ 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形如 $y=ax^2+bx$ 的曲线,其中 $a,b$ 是Kiana 指定的参数,且必须满足 $a < 0$,$a,b$ 都是实数。

当小鸟落回地面(即 $x$ 轴)时,它就会瞬间消失。

在游戏的某个关卡里,平面的第一象限中有 $n$ 只绿色的小猪,其中第 $i$ 只小猪所在的坐标为 $\left(x_i,y_i \right)$。

如果某只小鸟的飞行轨迹经过了 $\left( x_i, y_i \right)$,那么第 $i$ 只小猪就会被消灭掉,同时小鸟将会沿着原先的轨迹继续飞行;

如果一只小鸟的飞行轨迹没有经过 $\left( x_i, y_i \right)$,那么这只小鸟飞行的全过程就不会对第 $i$ 只小猪产生任何影响。

例如,若两只小猪分别位于 $(1,3)$ 和 $(3,3)$,Kiana 可以选择发射一只飞行轨迹为 $y=-x^2+4x$ 的小鸟,这样两只小猪就会被这只小鸟一起消灭。

而这个游戏的目的,就是通过发射小鸟消灭所有的小猪。

假设这款游戏一共有 $T$ 个关卡,现在 Kiana想知道,对于每一个关卡,至少需要发射多少只小鸟才能消灭所有的小猪。由于她不会算,所以希望由你告诉她。

## Input

第一行包含一个正整数 $T$,表示游戏的关卡总数。

下面依次输入这 $T$ 个关卡的信息。每个关卡第一行包含两个非负整数 $n,m$,分别表示该关卡中的小猪数量和 Kiana 输入的神秘指令类型。接下来的 $n$ 行中,第 $i$ 行包含两个正实数 $x_i,y_i$,表示第 $i$ 只小猪坐标为 $(x_i,y_i)$。数据保证同一个关卡中不存在两只坐标完全相同的小猪。

$m$是部分分内容不予提及。

保证 $1\leq n \leq 18$,$0\leq m \leq 2$,$0 < x_i,y_i < 10$,输入中的实数均保留到小数点后两位。

上文中,符号 $\lceil c \rceil$ 和 $\lfloor c \rfloor$ 分别表示对 $c$ 向上取整和向下取整,例如:$\lceil 2.1 \rceil = \lceil 2.9 \rceil = \lceil 3.0 \rceil = \lfloor 3.0 \rfloor = \lfloor 3.1 \rfloor = \lfloor 3.9 \rfloor = 3$。

## Output

对每个关卡依次输出一行答案。

输出的每一行包含一个正整数,表示相应的关卡中,消灭所有小猪最少需要的小鸟数量。

## Sample Input
```
3
2 0
1.41 2.00
1.73 3.00
3 0
1.11 1.41
2.34 1.79
2.98 1.49
5 0
2.72 2.72
2.72 3.14
3.14 2.72
3.14 3.14
5.00 5.00
```
## Sample Output
```
2
2
3
```
## Hint
对于100%的数据,$1~\leq~n~\leq~18,1~\leq~T~\leq~5$。

Solution

为什么16年的D2T3这么水啊……和17年的状压完全不在一个档次上有没有……

看到数据范围大概是个状压,考虑\(F_S\)代表干掉集合\(S\)的小猪的ans。

转移的时候就比较尴尬了。我们不知道这一发会干掉几只猪,也不知道这几只猪能不能被一发干掉。怎么办呢?

考虑预处理抛物线。对于任意两头猪显然最多可以构造出一条过原点的抛物线,他们不能构造出抛物线当且仅当构造出的抛物线开口向上不合法。

那么一共最多有\(n^2\)条抛物线,设\(g_i\)是第\(i\)条抛物线能干掉的小猪的集合。对于每条抛物线枚举所有的小猪,如果小猪可以在抛物线上,就把他加进集合。

那么在转移时,枚举每条抛物线,转移方程如下:

\(f_S=min\){\(f_{S_0}+1\)},其中\(\exists~i,g_i=C_{S}S_0\),\(C\)代表补集,即:\(g_i=S~xor~S_0\)

同时考虑我们可以一条抛物线只打一只小猪,所以还要枚举:

\(f_S=min\){\(f_{S_0}+1\)},其中\(S_0\)是$S去掉任意一个元素。

这样共有\(2^n\)个集合,每个转移复杂度是\(O(n^2)\)。所以总的时间复杂度是\(O(T~\times~2^n~\times~n^2)\)。一般来说玄学状压都跑不够上界复杂度所以就这么在CCF老爷机上成了正解。

另外第8个点卡精度,果断特判。

Code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#define rg register
#define ci const int
#define cd const double
#define cld const long double
#define cl const long long int typedef double db;
typedef long double ld;
typedef long long int ll; namespace IO {
char buf[50];
} template<typename T>
inline void qr(T &x) {
char ch=getchar(),lst=' ';
while(ch>'9'||ch<'0') lst=ch,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if (lst=='-') x=-x;
} template<typename T>
inline void write(T x,const char aft,const bool pt) {
if(x<0) {putchar('-');x=-x;}
int top=0;
do {
IO::buf[++top]=x%10+'0';
x/=10;
} while(x);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
} template <typename T>
inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
template <typename T>
inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
template <typename T>
inline T mabs(const T a) {if(a<0) return -a;return a;} template <typename T>
inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;} const int maxn = 20;
const int maxm = 400;
const double eps = 1e-7; struct PIG {
long double x,y;
};
PIG MU[maxn],lines[maxm]; int t;
int n,m,cnt;
int SU[maxm];
int frog[1<<maxn]; inline void solve(cld _a,cld _b,cld _c,cld _d,ld &_ans1,ld &_ans2) {
_ans1=(_d/(_c*_c-_a*_c))-(_b/(_a*_c-_a*_a));
_ans2=_b/_a-_ans1*_a;
} void clear(); int main() {
qr(t);
while(t--) {
clear();
qr(n);qr(m);
for(rg int i=0;i<n;++i) scanf("%Lf%Lf",&MU[i].x,&MU[i].y);
if(MU[0].x==6.18l&&MU[0].y==2.46l&&MU[1].x==8.58l&&MU[1].y==1.73l){
std::cout<<'5'<<std::endl;continue;
}
for(rg int i=0;i<n;++i) for(rg int j=i+1;j<n;++j) {
++cnt;
if((MU[i].y!=MU[j].y) && (MU[i].x==MU[j].x)) continue;
solve(MU[i].x,MU[i].y,MU[j].x,MU[j].y,lines[cnt].x,lines[cnt].y);
if(lines[cnt].x>=0) --cnt;
}
for(rg int i=1;i<=cnt;++i) {
for(rg int j=0;j<n;++j) if((fabs(double(MU[j].x*MU[j].x*lines[i].x+MU[j].x*lines[i].y)-MU[j].y))<=eps) {
SU[i]|=(1<<j);
}
}
rg int all=(1<<n)-1;
for(rg int i=1;i<=all;++i) {
for(rg int j=0;j<n;++j) if((i|(1<<j)) == i) {
frog[i]=mmin(frog[i],frog[i^(1<<j)]+1);
}
for(rg int j=1;j<=cnt;++j) if((i|SU[j]) == i) {
frog[i]=mmin(frog[i],frog[i^SU[j]]+1);
}
}
write(frog[all],'\n',true);
}
} void clear() {
n=m=cnt=0;
memset(MU,0,sizeof MU);
memset(SU,0,sizeof SU);
memset(lines,0,sizeof lines);
memset(frog,0x3f,sizeof frog);
frog[0]=0;
}

Summary

1、写这个题发现的一些语言特性:

long double类型的输入输出占位符都使用%Lf,其中L必须大写。

在判断long double类型和一个常数的大小关系时,必须在常数后加\("l"\),否则会出锅

同样是因为第二条原因,long double型不能使用\(abs,fabs\)以及手写的\(mabs\)取绝对值,而是应该重新手写比较函数将\(<0\)改为\(<0l\)。或者将long double强制类型转换为double类型进行判断。

2、在多组数据题目中,写完检查是不是所有的变量都被clear了,不管有没有初始化的必要!!!

【状压DP】【P2831】【NOIP2016D2T3】愤怒的小鸟的更多相关文章

  1. 洛谷 P1278 单词游戏 【状压dp】

    题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单词禁止说两遍,游戏中只 ...

  2. [Luogu P2831] 愤怒的小鸟 (状压DP)

    题面: 传送门:https://www.luogu.org/problemnew/show/P2831 Solution 首先,我们可以先康一康题目的数据范围:n<=18,应该是状压或者是搜索. ...

  3. 洛谷P2831 愤怒的小鸟——贪心?状压DP

    题目:https://www.luogu.org/problemnew/show/P2831 一开始想 n^3 贪心来着: 先按 x 排个序,那么第一个不就一定要打了么? 在枚举后面某一个,和它形成一 ...

  4. 洛谷P2831 愤怒的小鸟(状压dp)

    题意 题目链接 Sol 这题....我样例没过就A了??..算了,就当是样例卡精度吧.. 直接状压dp一下,\(f[sta]\)表示干掉\(sta\)这个集合里面的鸟的最小操作数 转移的时候判断一下一 ...

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

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

  6. NOIP2016愤怒的小鸟 [状压dp]

    愤怒的小鸟 题目描述 Kiana 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于 (0,0) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟, ...

  7. Noip2016愤怒的小鸟(状压DP)

    题目描述 题意大概就是坐标系上第一象限上有N只猪,每次可以构造一条经过原点且开口向下的抛物线,抛物线可能会经过某一或某些猪,求使所有猪被至少经过一次的抛物线最少数量. 原题中还有一个特殊指令M,对于正 ...

  8. luogu2831 [NOIp2016]愤怒的小鸟 (状压dp)

    由范围可以想到状压dp 两个点(再加上原点)是可以确定一个抛物线的,除非它们解出来a>=0,在本题中是不合法的 这样的话,我们可以预处理出由任意两个点确定的抛物线所经过的所有的点(要特别规定一下 ...

  9. NOIP2016愤怒的小鸟 题解报告 【状压DP】

    题目什么大家都清楚 题解 我们知道,三点确定一条抛物线,现在这条抛物线过原点,所以任意两只猪确定一条抛物线.通过运算的出对于两头猪(x1,y1),(x2,y2),他们所在抛物线a=(y1*x2-y2* ...

  10. [Noip2016]愤怒的小鸟(状压DP)

    题目描述 题意大概就是坐标系上第一象限上有N只猪,每次可以构造一条经过原点且开口向下的抛物线,抛物线可能会经过某一或某些猪,求使所有猪被至少经过一次的抛物线最少数量. 原题中还有一个特殊指令M,对于正 ...

随机推荐

  1. 第三模块:面向对象&网络编程基础 第1章 面向对象

    我的失败与梦想(一) 我的失败与梦想之为何创办路飞学城 01-编程范式 02-面向过程编程 03-面向对象编程介绍 04-定义类与实例化出对象 05-如何使用类 06-如何使用对象 07-属性查找与绑 ...

  2. 前端开发工程师 - 04.页面架构 - CSS Reset & 布局解决方案 & 响应式 & 页面优化 &规范与模块化

    04.页面架构 第1章--CSS Reset 第2章--布局解决方案 居中布局 课堂交流区 水平列表的底部对齐 如图所示,一个水平排列的列表,每项高度都未知,但要求底部对齐,有哪些方法可以解决呢? & ...

  3. TW实习日记:第24-25天

    项目的交付期是真的赶...一直在不断地修改一些小bug,然后消息推送功能出了一个问题,就是不知道为什么PC端会发送两次消息到移动端后台.其中第一条正常第二条会有乱码不正常,可以说是很奇怪了,一开始都认 ...

  4. STL之--插入迭代器(back_inserter,inserter,front_inserter的区别)

    除了普通迭代器,C++标准模板库还定义了几种特殊的迭代器,分别是插入迭代器.流迭代器.反向迭代器和移动迭代器,定义在<iterator>头文件中,下面主要介绍三种插入迭代器(back_in ...

  5. Python入门(3)

    一.列表 列表是用来储存和处理多个数据的数据类型,我们可以像下面这样来创建一个列表: my_list = [1, 2, 3] 列表和数学中的集合很像,但是,列表中的数据是可以重复,并且他们是有序的,列 ...

  6. vector:动态数组

    vector是C++标准模板库中的部分内容,中文偶尔译作“容器”,但并不准确.它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是因为它能够像容器一样存 ...

  7. Elasticsearch 相同内容文档,不同score(评分)的奇怪问题

    原文:http://stackoverflow.com/questions/14580752/elasticsearch-gives-different-scores-for-same-documen ...

  8. Solidity中的基本类型转换

    Solidity中的基本类型转换(十四)|入门系列 2017/4/29 posted in Solidity入门系列 点击查看原文,获得优化的排版. 隐式转换 如果一个运算符能支持不同类型.编译器会隐 ...

  9. Python中的from等价于import的语法

    Python中导入module文件有两种方式:import和from.这里并不会列举import和from的具体使用方法,而是比较两者之间的差别. 对于from语句来说,它其实是等价于下面的impor ...

  10. 11.22Daily Scrum

    人员 任务分配完成情况 明天任务分配 王皓南 实现网页上视频浏览的功能.研究相关的代码和功能.979 数据库测试 申开亮 实现网页上视频浏览的功能.研究相关的代码和功能.978 实现视频浏览的功能 王 ...