【BZOJ5299】【CQOI2018】解锁屏幕(动态规划,状态压缩)

题面

BZOJ

洛谷

Description

使用过Android手机的同学一定对手势解锁屏幕不陌生。Android的解锁屏幕由3x3个点组成,手指在屏幕上画一条

线将其中一些点连接起来,即可构成一个解锁图案。如下面三个例子所示:

画线时还需要遵循一些规则

1.连接的点数不能少于4个。也就是说只连接两个点或者三个点会提示错误。

2.两个点之间的连线不能弯曲。

3.每个点只能"使用"一次,不可重复。这里的"使用"是指手指划过一个点,该点变绿。

4.两个点之间的连线不能"跨过"另一个点,除非那个点之前已经被"使用"过了。

对于最后一条规则,参见下图的解释。左边两幅图违反了该规则:而右边两幅图(分别为2→4→1→3→6和→5→4→1→9→2)

则没有违反规则,因为在"跨过"点时,点已经被"使用"过了。

现在工程师希望改进解锁屏幕,增减点的数目,并移动点的位置,不再是一个九宫格形状,但保持上述画线的规则不变。

请计算新的解锁屏幕上,一共有多少满足规则的画线方案。

Input

输入文件第一行,为一个整数n,表示点的数目。

接下来n行,每行两个空格分开的整数xi和yi,表示每个点的坐标。

-1000≤xi,Yi≤l000,1≤n<20。各点坐标不相同

Output

输出文件共一行,为题目所求方案数除以100000007的余数。

Sample Input

4

0 0

1 1

2 2

3 3

Sample Output

8

解释:设4个点编号为1到4,方案有1→2→3→4,2→1→3→4,3→2→1→4,2→3→1→4,

及其镜像4→3→2→1,3→4→2→1,2→3→4→1,3→2→4→1.

题解

状压\(dp\),坑的死

首先好好观察一下模数,它TM不是\(10^9+7\)

。。。

然后考虑状压

设\(f[i][j]\)表示当前状态是\(i\),当前位置结尾的点是\(j\)的方案数

暴力枚举一下个连接谁,检查它们中间的点是否都已经被选择

如果每次都\(check\)一下,复杂度就会变成\(O(2^nn^3)\)

提前预处理出任意两个点之间的集合,这一步的复杂度是\(O(n^3)\)

计算是否贡献的时候,不要计算出斜率再计算,这样会掉精度

把斜率乘到两边就行了。

然后做\(dp\)的时候就可以\(O(1)\)检查了

这样复杂度就是\(O(n^3+2^nn^2)\),并且不满。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<set>
  8. #include<map>
  9. #include<vector>
  10. #include<queue>
  11. using namespace std;
  12. #define ll long long
  13. #define RG register
  14. #define MOD 100000007
  15. inline int read()
  16. {
  17. RG int x=0,t=1;RG char ch=getchar();
  18. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  19. if(ch=='-')t=-1,ch=getchar();
  20. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  21. return x*t;
  22. }
  23. int n,X[20],Y[20];
  24. int g[20][20];
  25. int f[20][1<<20];
  26. void update(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
  27. int main()
  28. {
  29. n=read();
  30. for(int i=0;i<n;++i)X[i]=read(),Y[i]=read();
  31. for(RG int i=0;i<n;++i)
  32. for(RG int j=0;j<n;++j)
  33. {
  34. if(i==j)continue;
  35. for(RG int k=0;k<n;++k)
  36. {
  37. if(k==i||k==j)continue;
  38. if(X[k]<X[i]&&X[k]<X[j])continue;
  39. if(X[k]>X[i]&&X[k]>X[j])continue;
  40. if(Y[k]<Y[i]&&Y[k]<Y[j])continue;
  41. if(Y[k]>Y[i]&&Y[k]>Y[j])continue;
  42. if(Y[i]==Y[k])
  43. {
  44. if(Y[j]==Y[k])g[i][j]|=(1<<k);
  45. continue;
  46. }
  47. if(Y[j]==Y[k])continue;
  48. if((X[i]-X[k])*(Y[j]-Y[k])==(X[j]-X[k])*(Y[i]-Y[k]))g[i][j]|=(1<<k);
  49. }
  50. }
  51. for(RG int i=0;i<n;++i)f[i][1<<i]=1;
  52. for(RG int t=0;t<(1<<n);++t)
  53. for(RG int i=0;i<n;++i)
  54. {
  55. if(!(t&(1<<i)))continue;
  56. if(!f[i][t])continue;
  57. for(RG int j=0;j<n;++j)
  58. {
  59. if(t&(1<<j))continue;
  60. if((g[i][j]&t)!=g[i][j])continue;
  61. update(f[j][t|(1<<j)],f[i][t]);
  62. }
  63. }
  64. int ans=0;
  65. for(RG int t=0;t<(1<<n);++t)
  66. {
  67. int tot=0;
  68. for(RG int i=t;i;i-=i&(-i))++tot;
  69. if(tot<4)continue;
  70. for(RG int i=0;i<n;++i)
  71. if(t&(1<<i))update(ans,f[i][t]);
  72. }
  73. printf("%d\n",ans);
  74. return 0;
  75. }

【BZOJ5299】【CQOI2018】解锁屏幕(动态规划,状态压缩)的更多相关文章

  1. bzoj5299: [Cqoi2018]解锁屏幕

    题目链接 bzoj 5299: [Cqoi2018]解锁屏幕 题解 很水的装压dp,相信没人需要看题解.... dp[i][j]表示状态为i最后一个到的点为j,然后转移就很好写了 不过 我读入优化没读 ...

  2. BZOJ5299:[CQOI2018]解锁屏幕(状压DP)

    Description 使用过Android手机的同学一定对手势解锁屏幕不陌生.Android的解锁屏幕由3x3个点组成,手指在屏幕上画一条 线将其中一些点连接起来,即可构成一个解锁图案.如下面三个例 ...

  3. BZOJ5299 [Cqoi2018]解锁屏幕 【状压dp】

    题目链接 BZOJ5299 题解 就一个毒瘤卡常题..写了那么久 设\(f[i][s]\)表示选了集合\(s\)中的点,最后一个是\(i\),进行转移 要先预处理出两点间的点,然后卡卡常就可以过了 # ...

  4. [Luogu] P4460 [CQOI2018]解锁屏幕

    题目背景 使用过Android 手机的同学一定对手势解锁屏幕不陌生.Android 的解锁屏幕由3X3 个点组成,手指在屏幕上画一条线,将其中一些点连接起来,即可构成一个解锁图案.如下面三个例子所示: ...

  5. P4460 [CQOI2018]解锁屏幕

    算是我比较擅长的类型,自己想想就会了.普通小状压,状态傻子都能想出来.一开始裸的枚举T了,30.后来与处理之后跑的飞起,就是不对,还是30分.后来看讨论版...mod竟然是1e8+7!!!这不有毒吗. ...

  6. [动态规划]状态压缩DP小结

     1.小技巧 枚举集合S的子集:for(int i = S; i > 0; i=(i-1)&S) 枚举包含S的集合:for(int i = S; i < (1<<n); ...

  7. [POJ 2923] Relocation (动态规划 状态压缩)

    题目链接:http://poj.org/problem?id=2923 题目的大概意思是,有两辆车a和b,a车的最大承重为A,b车的最大承重为B.有n个家具需要从一个地方搬运到另一个地方,两辆车同时开 ...

  8. POJ 1185 炮兵阵地(动态规划+状态压缩)

    炮兵阵地 Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原( ...

  9. ACM学习历程—HDU1584 蜘蛛牌(动态规划 && 状态压缩 || 区间DP)

    Description 蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么这些牌也跟着一起 ...

  10. HDOJ-1074(动态规划+状态压缩)

    Doing Homework HDOJ-1074 1.本题主要用的是状态压缩的方法,将每种状态用二进制压缩表示 2.状态转移方程:dp[i|(1<<j)]=min(dp[i|(1<& ...

随机推荐

  1. 应用监控Metrics

    应用监控Metrics 一.Metrics简介        应用监控系统Metrics由Metrics.NET+InfluxDB+Grafana组合而成,通过客户端Metrics.NET在业务代码中 ...

  2. 蓝牙BLE4.0的LL层数据和L2CAP层数据的区分与理解

    一直搞不太清楚蓝牙BLE协议,不知道LL层和L2CAP层是如何划分的,后来博士给我讲了讲就理解了,写下来,做个记录: 1. 我们知道,除了蓝牙5.1新出的CTE,所有的BLE都是如下类型的包: 对于连 ...

  3. C/C++心得-理解指针

    上一篇笔者用自己那不是怎么好理解的逻辑介绍了内存和C中的基本数据类型,现在笔者再根据自己重新所学来说说C语言中的指针. 理解指针才能真正的算C语言入门.也许是我大学期间太关注前端UE,也许是当初开始学 ...

  4. HDU 6370 Werewolf 【并查集】

    任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6370 Werewolf Time Limit: 2000/1000 MS (Java/Others)   ...

  5. 面试准备——(二)专业知识(4)C/C++语言

    1. 预处理 断言 assert的功能,assert(statement),如果statement为真则程序继续执行,为假则整个程序中断退出 3. #define [ #ifndef DISKSIM_ ...

  6. [转]MFC子线程中更新控件内容的两种办法

    一.概述 每个系统中都有线程(至少都有一个主线程),而线程最重要的作用就是并行处理,提高软件的并发率.针对界面来说,还能提高界面的响应能力.一般的,为了应用的稳定性,在数据处理等耗时操作会单独在一个线 ...

  7. Spring 通过XML配置装配Bean

    使用XML装配Bean需要定义对于的XML,需要引入对应的XML模式(XSD)文件,这些文件会定义配置Spring Bean的一些元素,简单的配置如下: <?xml version=" ...

  8. 【luogu P3393 逃离僵尸岛】 题解

    题目链接:https://www.luogu.org/problemnew/show/P3393 被占领的点可以先连在一个点上然后只需要对这一个点bfs一遍就可以求所有的危险点 #include &l ...

  9. 跟我一起写 Makefile (Linux )

    1.昨天 在 Linux 下用  touch  指令 新建了一个  hello.c 并且使用 vim 编辑器 写了代码 ,使用 gcc 指令编译 最后运行 成功了 .具体方式如下: 在Linux 根目 ...

  10. Struts2知识点小结汇总

    Struts2部分 1. JavaEE软件三层结构和MVC的区别? JavaEE软件三层机构是由sun公司提供JavaEE开发规范的:Web层(表现层).业务逻辑层.数据持久层.[其中WEB层会使用前 ...