【状压DP】【P2831】【NOIP2016D2T3】愤怒的小鸟

传送门

Description

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

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

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

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

在游戏的某个关卡里,平面的第一象限中有 n 只绿色的小猪,其中第 i 只小猪所在的坐标为 (xi,yi)

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

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

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

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

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

## Input

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

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

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

保证 1n180m20<xi,yi<10,输入中的实数均保留到小数点后两位。

上文中,符号 cc 分别表示对 c 向上取整和向下取整,例如:2.1=2.9=3.0=3.0=3.1=3.9=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  n  181  T  5

Solution

为什么16年的D2T3这么水啊……和17年的状压完全不在一个档次上有没有……
看到数据范围大概是个状压,考虑FS代表干掉集合S的小猪的ans。
转移的时候就比较尴尬了。我们不知道这一发会干掉几只猪,也不知道这几只猪能不能被一发干掉。怎么办呢?
考虑预处理抛物线。对于任意两头猪显然最多可以构造出一条过原点的抛物线,他们不能构造出抛物线当且仅当构造出的抛物线开口向上不合法。
那么一共最多有n2条抛物线,设gi是第i条抛物线能干掉的小猪的集合。对于每条抛物线枚举所有的小猪,如果小猪可以在抛物线上,就把他加进集合。
那么在转移时,枚举每条抛物线,转移方程如下:
fS=min{fS0+1},其中 igi=CSS0C代表补集,即:gi=S xor S0
同时考虑我们可以一条抛物线只打一只小猪,所以还要枚举:
fS=min{fS0+1},其中S0是$S去掉任意一个元素。
这样共有2n个集合,每个转移复杂度是O(n2)。所以总的时间复杂度是O(T × 2n × n2)。一般来说玄学状压都跑不够上界复杂度所以就这么在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了,不管有没有初始化的必要!!!

posted @   一扶苏一  阅读(194)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示