解:首先,n<=20的直接暴力建图然后状压哈密顿回路,相信大家都会。固定1为起点,fi,s表示结尾为i点,状态为s。每次遍历i的出边转移,最后遍历1的出边统计答案。n22n

然后就是正经题解了。先考虑K = 1的时候。对于一个子树,我们发现它只有三个地方有出边,左右上。而除此之外内部怎么连是没关系的,只要满足每个点都经过就行了。

于是就设fi,j表示以i为根的子树中,与外界连通状态为j的方案数。0表示从左右出去且经过根节点,1表示从左上出去,2表示从右上出去,3表示从左右出去且不经过根节点(这是为了方便转移才设的)。

每次合并两个子树而非一次做整个根节点(方便之后K > 1的时候),于是我们考虑每个状态如何被转移来:

  • 0由所有子树中某两个相邻的12状态和两边的0状态转移来。也就是从0 + 0(前面有两个相邻的12)或1 + 2转移来。
  • 1由最后的一个1和前面的所有0转移过来。也就是3 + 1。
  • 2由最前面的一个2和后面的所有0转移过来,也就是2 + 0,注意要特判当前子树为第一个子树时的情况。
  • 3由所有0转移过来,也就是0 + 0。

于是我们得到了一个O(n)的树形DP,注意根节点最后一个子树合并上来的时候,状态0还有一种情况就是最左2 + 中间0 + 最右1也就是2 + 1的转移。

然后输出f[1][0]即可获得30分,配合暴力有50分。

 #include <bits/stdc++.h>

 const int N = , MO = ;

 struct Edge {
int nex, v;
}edge[N << ]; int tp; int e[N], n, K, fa[N], stk[N], top, pw[];
int f[][];
std::vector<int> G[N];
std::bitset<N> bt[N]; inline void add(int x, int y) {
tp++;
//printf("add %d %d \n", x, y);
bt[x].set(y);
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} void DFS(int x) {
if(!G[x].size()) {
stk[++top] = x;
}
for(int i = ; i < (int)G[x].size(); i++) {
int y = G[x][i];
DFS(y);
}
return;
} inline void link(int x, int y) {
if(bt[x][y]) {
return;
}
add(x, y);
add(y, x);
return;
} inline void out(int x) {
for(int i = ; i < n; i++) {
printf("%d", (x >> i) & );
}
return;
} namespace k1 {
int f[N][];
void DFS(int x) {
if(!G[x].size()) {
f[x][] = f[x][] = f[x][] = ;
//printf("x = %d %d %d %d %d \n", x, f[x][0], f[x][1], f[x][2], f[x][3]);
return;
}
f[x][] = ;
for(int i = ; i < G[x].size(); i++) {
int y = G[x][i];
DFS(y);
///merge
int t0 = (1ll * f[x][] * f[y][] % MO + 1ll * f[x][] * f[y][] % MO) % MO;
int t1 = 1ll * f[x][] * f[y][] % MO;
int t2 = i ? 1ll * f[x][] * f[y][] % MO : f[y][];
int t3 = 1ll * f[x][] * f[y][] % MO;
if(x == && i == G[x].size() - ) {
(t0 += 1ll * f[x][] * f[y][] % MO) %= MO;
}
f[x][] = t0;
f[x][] = t1;
f[x][] = t2;
f[x][] = t3;
}
//printf("x = %d %d %d %d %d \n", x, f[x][0], f[x][1], f[x][2], f[x][3]);
return;
}
inline void solve() {
DFS();
printf("%d\n", f[][]);
return;
}
} int main() { //freopen("polygon.in", "r", stdin);
//freopen("polygon.out", "w", stdout); scanf("%d%d", &n, &K); for(int i = , x; i <= n; i++) {
scanf("%d", &x);
add(x, i); add(i, x);
fa[i] = x;
G[x].push_back(i);
} for(int i = ; i <= n; i++) std::sort(G[i].begin(), G[i].end()); if(K == ) {
k1::solve();
return ;
} DFS(); for(int i = ; i <= top; i++) {
for(int j = ; j <= K; j++) {
int temp = i + j;
if(temp > top) {
temp %= top;
}
if(!temp) {
temp = top;
}
link(stk[i], stk[temp]);
}
} int lm = ( << n);
for(int i = ; i <= lm; i++) pw[i] = pw[i >> ] + ;
f[][] = ;
for(int s = ; s < lm; s++) {
for(int x = ; x <= n; x++) {
/// f[x][s]
if(!f[x][s]) continue;
//printf("f %d ", x); out(s); printf(" = %d \n", f[x][s]);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if((s >> (y - )) & ) {
continue;
}
(f[y][s | ( << (y - ))] += f[x][s]) %= MO;
}
}
}
int ans = ;
for(int i = e[]; i; i = edge[i].nex) {
int y = edge[i].v;
ans = (ans + f[y][lm - ]) % MO;
}
printf("%lld\n", 1ll * ans * (MO + ) / % MO);
return ;
}

50分代码

接下来说说K > 1的部分:

LOJ#2723 多边形的更多相关文章

  1. Loj #3056. 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

  2. LOJ 3056 「HNOI2019」多边形——模型转化+树形DP

    题目:https://loj.ac/problem/3056 只会写暴搜.用哈希记忆化之类的. #include<cstdio> #include<cstring> #incl ...

  3. 【loj - 3056】 「HNOI2019」多边形

    目录 description solution accepted code details description 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时 ...

  4. LOJ 2548 「JSOI2018」绝地反击 ——二分图匹配+网络流手动退流

    题目:https://loj.ac/problem/2548 如果知道正多边形的顶点,就是二分答案.二分图匹配.于是写了个暴力枚举多边形顶点的,还很愚蠢地把第一个顶点枚举到 2*pi ,其实只要 \( ...

  5. Loj 2008 小凸想跑步

    Loj 2008 小凸想跑步 \(S(P,p_0,p_1)<S(P,p_i,p_{i+1})\) 这个约束条件对于 \(P_x,P_y\) 是线性的,即将面积用向量叉积表示,暴力拆开,可得到 \ ...

  6. LOJ 一本通一句话题解系列:

    第一部分 基础算法 第 1 章 贪心算法 1):「一本通 1.1 例 1」活动安排:按照结束时间排序,然后扫一遍就可以了. 2):「一本通 1.1 例 2」种树:首先要尽量的往区间重叠的部分种树,先按 ...

  7. [LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC

    [LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC 试题描述 九条可怜是一个爱玩游戏的女孩子. 最近她在玩一个无双割草类的游戏,平面上有 \(n\) 个敌人,每一个敌人的坐标为 ...

  8. canvas快速绘制圆形、三角形、矩形、多边形

    想看前面整理的canvas常用API的同学可以点下面: canvas学习之API整理笔记(一) canvas学习之API整理笔记(二) 本系列文章涉及的所有代码都将上传至:项目代码github地址,喜 ...

  9. 任意多边形切割/裁剪(附C#代码实现)

    本实现主要参考了发表于2003年<软件学报>的<一个有效的多边形裁剪算法>(刘勇奎,高云,黄有群)这篇论文,所使用的理论与算法大都基于本文,对论文中部分阐述进行了详细解释,并提 ...

随机推荐

  1. nginx + flask + uwsgi + centos + python3 搭建web项目

    1. python3之前已经搭建好,安装flask,使用 pip3 intall flask,这个比较简单,就不过多介绍 2.我在 /usr/local/nginx/html3  (html3是我新建 ...

  2. 使用mysqlhelper可以连接mysql

    已经验证OK通过. 参考地址: https://www.oschina.net/code/snippet_579976_48967 https://files.cnblogs.com/files/mo ...

  3. C#中FormsAuthentication用法实例

    ....本文纯属抄袭....   using System; using System.Web; using System.Web.Security;   namespace AuthTest {   ...

  4. 什么是TLB?

    TLB:Translation Lookaside Buffer. 根据功能可以译为快表,直译可以翻译为旁路转换缓冲,也可以把它理解成页表缓冲.里面存放的是一些页表文件(虚拟地址到物理地址的转换表). ...

  5. 批处理基础知识-EXIT

    本文主要介绍批处理EXIT命令的使用. 阅读须知: 在开始阅读本文之前,您需要知道批处理CALL命令和ERRORLEVEL相关知识,若您没有接触过类似信息,建议goole或baidu. EXIT命令格 ...

  6. Selenium自动化测试-unittest单元测试框架使用

    一.什么是unittest 这里我们将要用的unittest是python的单元测试框架,它的官网是 https://docs.python.org/2/library/unittest.html,在 ...

  7. 在android中进行单元测试的步骤

    若不知道怎么配上面两个参数 

  8. 【Teradata SQL】创建数据库和表

    1.数据库perm大小为10G Create database testbase as perm=10E9,spool=10E9; 2.创建物理表 create multiset table stg( ...

  9. 修改json对象的每一个值

    function fun1(obj){ var names={}; /*for in 可以用于数组或者对象*/ for(var name in obj){ names[name] = obj[name ...

  10. c++11の数据竞争和互斥对象

    一.数据竞争的产生 在下面例子中: void function_1() { ; i < ; i++) { std::cout << "from function 1:&qu ...