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

题干:

题目背景

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

题目描述

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

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

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

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

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

对于最后一条规则,参见下图的解释。左边两幅图违反了该规则; 而右边两幅图(分别为2->--- 和6->-->->-) 则没有违反规则,因为在“跨过”点时,点已经被“使用”过了。

现在工程师希望改进解锁屏幕,增减点的数目,并移动点的位置,不再是一个九宫格形状,但保持上述画线的规则不变。请计算新的解锁屏幕上,一共有多少满足规则的画线方案。
输入输出格式
输入格式: 输入文件第一行,为一个整数n,表示点的数目。 接下来n 行,每行两个空格分开的整数xix_ixi​ 和yiy_iyi​,表示每个点的坐标。 输出格式: 输出文件共一行,为题目所求方案数除以100000007 的余数。

30

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(register int i = a;i <= n;++i)
#define lv(i,a,n) for(register int i = a;i >= n;--i)
#define clean(a) memset(a,0,sizeof(a))
const int INF = << ;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
char c;
bool op = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(op) x = -x;
}
template <class T>
void write(T x)
{
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
}
const int mod = 1e9 + ;
const int N = ;
int dp[ << N][N];
int x[N],y[N],n,ans;
/*void dfs(int now,int u,int len)//zhuangtai.xianzaidedian,changdu
{
if(dp[now][u]) return dp[now][u];
for(int i = 1;i <= n;i++)
{
if(now & (1 << (i - 1)) == 0)
{
int ok = 0;
duke(j,1,n)
{
if(now & (1 << (i - 1)) == 0)
{
if(check(u,j,i) == false)
{
ok = 1;
break;
}
}
}
if(ok == 0)
{
dfs(now | (1 << (i - 1)),i,len + 1);
dp[now][u] += dp[now | (1 << (i - 1))]
}
}
}
}*/
bool check(int a,int b,int c)
{
/*if(a == 1 && c == 3 && b == 2)
printf("%d %d %d\n",a,b,c);*/
if((y[b] - y[a]) * (x[c] - x[b]) != (y[c] - y[b]) * (x[b] - x[a]))
return true;
if(x[a] > x[b] && x[c] > x[b])
return true;
if(x[a] < x[b] && x[c] < x[b])
return true;
if(y[a] > y[b] && y[c] > y[b])
return true;
if(y[a] < y[b] && y[c] < y[b])
return true;
return false;
}
void p(int now)
{
duke(i,,n)
{
if((now & ( << (i - ))) != )
printf("");
else
printf("");
}
}
int main()
{
read(n);
duke(i,,n)
read(x[i]),read(y[i]);
duke(i,,n - )
{
dp[ << i][i + ] = ;
}
for(int now = ;now <= ( << n) - ;now++)
{
duke(i,,n)
{
if((now & ( << (i - ))) != )
{
duke(j,,n)
{
if((now & ( << (j - ))) != && i != j)
{
int ok = ;
duke(k,,n)
{
if((now & ( << (k - ))) == )
if(check(i,k,j) == false)
{
ok = ;//cout<<i<<" "<<j<<" "<<k<<endl;
break;
}
}
if(ok == )
{
dp[now][i] += dp[now - ( << (i - ))][j];
// p(now),printf(" ");cout<<i<<" "<<j;printf(" ");p(now - (1 << (i - 1)));
// puts("");
dp[now][i] %= mod;
}
}
}
}
}
int tot = ;
duke(i,,n - )
{
if((now & ( << i)) != )
tot++;
}
if(tot >= )
{
duke(i,,n)
{
if((now & ( << (i - ))) != )
ans += dp[now][i],ans %= mod;
}
}
}
// ans += 1;
// ans /= 2;
/*duke(i,0,(1 << n) - 1)
{
duke(j,1,n)
if((i & (1 << (j - 1))) != 0)
p(i),printf(" "),cout<<dp[i][j]<<endl;
}*/
printf("%d\n",ans);
return ;
}

AC代码:

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(register int i = a;i <= n;++i)
#define lv(i,a,n) for(register int i = a;i >= n;--i)
#define clean(a) memset(a,0,sizeof(a))
const int INF = << ;
typedef long long ll;
typedef double db;
template <class T> void read(T &x)
{
char c;
bool op = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(op) x = -x;
}
template <class T>
void write(T x)
{
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
}
const int mod = 1e8 + ;
const int N = ;
int dp[ << N][N];
int x[N],y[N],n,ans;
bool check(int a,int b,int c)
{
/*if(a == 1 && c == 3 && b == 2)
printf("%d %d %d\n",a,b,c);*/
if((y[b] - y[a]) * (x[c] - x[b]) != (y[c] - y[b]) * (x[b] - x[a]))
return true;
if(x[a] > x[b] && x[c] > x[b])
return true;
if(x[a] < x[b] && x[c] < x[b])
return true;
if(y[a] > y[b] && y[c] > y[b])
return true;
if(y[a] < y[b] && y[c] < y[b])
return true;
return false;
}
void p(int now)
{
duke(i,,n)
{
if((now & ( << (i - ))) != )
printf("");
else
printf("");
}
}
vector <int> mp[N][N];
void init(int x,int y)
{
for(int i = ;i <= n;i++)
{
if(check(x,i,y) == false)
{
mp[x][y].push_back(i);
}
}
}
int main()
{
read(n);
duke(i,,n)
read(x[i]),read(y[i]);
duke(i,,n - )
{
dp[ << i][i + ] = ;
}
duke(i,,n)
duke(j,,n)
init(i,j);
for(int now = ;now <= ( << n) - ;now++)
{
duke(i,,n)
{
if((now & ( << (i - ))) != )
{
duke(j,,n)
{
if((now & ( << (j - ))) != && i != j)
{
int ok = ;
duke(f,,(int)mp[i][j].size() - )
{
int k = mp[i][j][f];
if((now & ( << (k - ))) == )
{
ok = ;//cout<<i<<" "<<j<<" "<<k<<endl;
break;
}
}
if(ok == )
{
dp[now][i] += dp[now - ( << (i - ))][j];
// p(now),printf(" ");cout<<i<<" "<<j;printf(" ");p(now - (1 << (i - 1)));
// puts("");
dp[now][i] %= mod;
}
}
}
}
}
int tot = ;
duke(i,,n - )
{
if((now & ( << i)) != )
tot++;
}
if(tot >= )
{
duke(i,,n)
{
if((now & ( << (i - ))) != )
ans += dp[now][i],ans %= mod;
}
}
}
// ans += 1;
// ans /= 2;
/*duke(i,0,(1 << n) - 1)
{
duke(j,1,n)
if((i & (1 << (j - 1))) != 0)
p(i),printf(" "),cout<<dp[i][j]<<endl;
}*/
printf("%d\n",ans);
return ;
}

代码:

P4460 [CQOI2018]解锁屏幕的更多相关文章

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

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

  2. bzoj5299: [Cqoi2018]解锁屏幕

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

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

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

  4. [CQOI2018]解锁屏幕

    嘟嘟嘟 这题感觉真的很简单-- \(O(n ^ 2 logn)\)的做法特别好理解,但得开O2. 看数据范围,肯定是状压dp.但刚开始我没想通状压啥,因为点与点之间还有顺序问题.但后来发现这个顺序是子 ...

  5. 【[CQOI2018]解锁屏幕】

    状压这个东西好像没有什么能优化的高级东西,像什么斜率优化,单调队列在状压的优化上都很少见 而最常见的状压优化就是预处理优化了, 这道题就预处理一下所有点对之间连线上的点,之后压成状态就能做到\(O(2 ...

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

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

  7. BZOJ 5299: [Cqoi2018]解锁屏幕

    状压DP #include<cstdio> using namespace std; const int mod=1e8+7; int F[1000005][25],dis[25][25] ...

  8. bzoj 5299: [Cqoi2018]解锁屏幕 状压dp+二进制

    比较简单的状压 dp,令 $f[S][i]$ 表示已经经过的点集为 $S$,且最后一个访问的位置为 $i$ 的方案数. 然后随便转移一下就可以了,可以用 $lowbit$ 来优化一下枚举. code: ...

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

    [BZOJ5299][CQOI2018]解锁屏幕(动态规划,状态压缩) 题面 BZOJ 洛谷 Description 使用过Android手机的同学一定对手势解锁屏幕不陌生.Android的解锁屏幕由 ...

随机推荐

  1. Linux中CentOS网络配置以及与Xshell建立远程连接

    为centos配置网络 (1)第一步 点开虚拟机的设置,如下图做相关的设置: 网络连接要选择桥接模式,其他的勾选就按照上图的即可,勾选完成点击确定. (2)第二步 点击VMware的编辑选项,找到“虚 ...

  2. 4.model 字段

    一.字段名 字段名 类型 参数 AutoField(Field) - int自增列, 必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自 ...

  3. *** 红包书用法 及 ubuntu全局配置

    使用教程 http://go.wasai.org/sswiki https://home.maysoul.com/wiki/doku.php?id=shadowsocks ubuntu使用教程 htt ...

  4. 3.2.8 sed 的运作

        sed 的工作方式相当直接.命令行上的每个文件会依次打开与读取.如果没有文件,则使用标准输入,文件名“-”(单个破折号)可用于表示标准输入.       [many@avention Desk ...

  5. JS判断滚动条是否停止滚动

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. angular(转)

    学习之前可以看看 知乎上讨论angularjs优缺点 帮你选择框架的网站 同类主流框架对比 教程 angularjs在慕课网 angularjs在51cto angularjs在图灵社区 社区 Ang ...

  7. Java AOP

    AOP 今天我要和大家分享的是 AOP(Aspect-Oriented Programming)这个东西,名字与 OOP 仅差一个字母,其实它是对 OOP 编程方式的一种补充,并非是取而代之.翻译过来 ...

  8. CentOS7 Firewall防火墙配置用法详解

    centos 7中防火墙是一个非常的强大的功能了,但对于centos 7中在防火墙中进行了升级了,下面我们一起来详细的看看关于centos 7中防火墙使用方法.   FirewallD 提供了支持网络 ...

  9. Form表单的action和onSubmit示例介绍

    action是form的属性,onSubmit为事件,要说执行的先后顺序,个人理解是onSubmit在先. 第一:action是form的属性,html5已经将其定义为必需的属性值,onSubmit为 ...

  10. bzoj1444 有趣的游戏(AC自动机+概率dp)

    题意: 给定n个长度为l的模式串,现在要用前m个大写字母生成一个随机串,每个字符有自己的出现几率,第一次出现的字符串获胜,求最终每个字符串的获胜几率. 分析: 容易想到先把所有的字符串建成一个AC自动 ...