[JZOJ4949]仙人球
题目大意
定义仙人球为一个无自环重边的、每个点最多属于一个简单环的无向连通图。
现在给定一个nn个点mm条边的仙人球,你要从其中选出至多KK个,使得这些点满足能在不经过其它没被选择的点的情况下互相连通。不能不选点。
求出方案数模109+710^9+7。
1≤n≤5×103,1≤K≤min(n,100)1\le n\le5\times10^3,1\le K\le\min(n,100)
题目分析
可以发现仙人球就是一堆环形成一个树形结构(孤立的单点也可以看做环)。
那么我们考虑使用动态规划。
设fi,jf_{i,j}表示做到第ii个环,以这个环为根的子仙人球总共选择了jj个节点,并且当前环的深度最小的点一定选择了的方案数。
考虑将环上每个点为根的子仙人球的信息放到点上,令hi,jh_{i,j}表示当前环第ii个点为根的子仙人球(如下图颜色圈中的各个块)选择了jj个节点的方案数。
hih_{i}可以很方便地由第ii个点的所有儿子的ff推出。
那么现在考虑知道了hih_{i}怎么求出ff。
现在我们相当于在一个环上有若干个关键点,第ii个关键点选择jj个点有hi,jh_{i,j}种方案。求整个环从11号点(环深度最小的点即顶点)开始向两边若干连续关键点选出点的方案。
我们令F0,i,jF_{0,i,j}表示从点11向后扩展到点ii,每个关键点都至少选出一个点,总共选出jj个点的方案数。F1,i,jF_{1,i,j}则是从最后一个点向前扩展到点ii,其它类似。
F0/1,i,jF_{0/1,i,j}通过hi,jh_{i,j}易得。
令tottot为环上关键点个数。我们得出这个以后,就可以通过
f_{x,j}=F_{0,tot,j}+\sum_{i=1}^{tot}F_{0,i,k}\sum_{l=i+2}^{tot}F_{1,l,j-k}
来计算 ff的值,后面那个sigma显然可以使用后缀和维护,而为什么是从i+2i+2开始枚举呢?因为如果我们算上 i+1i+1,那就会把整个环的关键点都有点选的情况计算上 tottot次。而式子前面那个 F0,tot,jF_{0,tot,j}就是把这种情况一次性算了。
那么知道了 ff,我们怎么统计答案呢?
设gi,jg_{i,j}表示做到第 ii个环,以这个环为根的子仙人球总共选择了jj个节点,并且当前环至少选了一个点的方案数。我们求答案时把所有 gi,jg_{i,j}加起来就行了。
怎么计算 gg呢?gg相当于在环上的连续一段关键点中选点。我们分两种情况讨论:一种是这连续的一段没有跨过第一个点和最后一个点的连边,另一种是这连续的一段跨过了第一个点和最后一个点的连边。
我们令 Gi,jG_{i,j}表示环上第 ii个关键点向前连续选点,选了jj个的方案数,方程和 FF是有点类似的。那么所有的Gi,jG_{i,j}求和就是第一种情况。
至于第二种情况呢?可以发现它其实就是从第一个点和最后一个点分别向两边延伸,和 ff的计算过程是差不多的,唯一的不同就是从最后一个点延伸那边不能一个点都不选,不然就会算重。
计算过程中不需要显式地弄gg出来,我只是为了统计方便弄了这个辅助变量。
所有过程都是 O(nK2)\mathrm O(nK^2)的。
代码实现
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
#include <stack>using namespace std;int read()
{int x=0,f=1;char ch=getchar();while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();return x*f;
}const int P=1000000007;
const int N=5050;
const int M=N<<1;
const int E=M<<1;
const int MAXK=105;int f[N][MAXK],g[N][MAXK],h[N][MAXK],F[2][N][MAXK],G[N][MAXK],sum[MAXK];
int last[N],bel[N],DFN[N],low[N];
int tov[E],rev[E],nxt[E];
stack<int> st;
int cir[N][N];
int idx,cnt,n,m,tot,K,ans,root;void insert(int x,int y,int r){tov[++tot]=y,rev[tot]=tot+r,nxt[tot]=last[x],last[x]=tot;}void tarjan(int x,int fe)
{DFN[x]=low[x]=++idx,st.push(x);for (int i=last[x],y;i;i=nxt[i])if (i!=fe)if (!DFN[y=tov[i]]) tarjan(y,rev[i]),low[x]=min(low[x],low[y]);else low[x]=min(low[x],DFN[y]);if (DFN[x]==low[x]){++cnt;int y;do{y=st.top(),cir[bel[y]=cnt][++cir[cnt][0]]=y,st.pop();}while (x!=y);for (int i=1;i*2<=cir[cnt][0];i++) swap(cir[cnt][i],cir[cnt][cir[cnt][0]+1-i]);if (x==1) root=cnt;}
}void dp(int cid,int fa)
{int son=cir[cid][0];for (int i,x,y,j=1;j<=son;j++)for (i=last[x=cir[cid][j]];i;i=nxt[i])if ((y=tov[i])!=fa&&bel[y]!=cid) dp(bel[y],x);for (int i,x,y,u,j=1;j<=son;j++){for (i=0;i<=K;i++) h[j][i]=0;h[j][1]=1;for (i=last[x=cir[cid][j]];i;i=nxt[i])if ((y=tov[i])!=fa&&(u=bel[y])!=cid)for (int k=K;k>=1;k--)for (int l=1;l<=K-k;l++)(h[j][k+l]+=1ll*h[j][k]*f[u][l]%P)%=P;}/*calculate G*/for (int i=1;i<=K;i++) G[1][i]=h[1][i];for (int i=2;i<=son;i++)for (int j=K;j>=1;j--){G[i][j]=h[i][j];for (int k=1;k<=K-j;k++) (G[i][j+k]+=1ll*G[i-1][j]*h[i][k]%P)%=P;}for (int i=1;i<=son;i++)for (int j=1;j<=K;j++)(g[cid][j]+=G[i][j])%=P;/*calculate F*/for (int i=1;i<=K;i++) F[0][1][i]=h[1][i];for (int i=2;i<=son;i++)for (int j=K;j>=1;j--){F[0][i][j]=0;for (int k=1;k<=K-j;k++) (F[0][i][j+k]+=1ll*F[0][i-1][j]*h[i][k]%P)%=P;}for (int i=1;i<=K;i++) F[1][son][i]=h[son][i];for (int i=son-1;i>=1;i--)for (int j=K;j>=1;j--){F[1][i][j]=0;for (int k=1;k<=K-j;k++) (F[1][i][j+k]+=1ll*F[1][i+1][j]*h[i][k]%P)%=P;}for (int i=0;i<=K;i++) sum[i]=0;for (int i=1;i<=K;i++) f[cid][i]=F[1][1][i];sum[0]=1;for (int i=son-1;i>=1;i--){for (int j=1;j<=K;j++)for (int k=0;k<=K-j;k++){(f[cid][j+k]+=1ll*F[0][i][j]*sum[k]%P)%=P;if (k) (g[cid][j+k]+=1ll*F[0][i][j]*sum[k]%P)%=P;}for (int j=1;j<=K;j++) (sum[j]+=F[1][i+1][j])%=P;}
}void calc()
{ans=0;for (int i=1;i<=cnt;i++)for (int j=1;j<=K;j++)(ans+=g[i][j])%=P;
}int main()
{freopen("cactus.in","r",stdin),freopen("cactus.out","w",stdout);n=read(),m=read(),K=read();for (int i=1,x,y;i<=m;i++) x=read(),y=read(),insert(x,y,1),insert(y,x,-1);tarjan(1,0),dp(root,0),calc();printf("%d\n",ans);fclose(stdin),fclose(stdout);return 0;
}
[JZOJ4949]仙人球相关推荐
- HDU2153 仙人球的残影【数学计算+水题】
仙人球的残影 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...
- 仙人球模型matlab,3dmax软件如何制作带刺的仙人球模型?
你知道用3dmax软件如何制作带刺的仙人球模型?本文小编将为大家带来用3DMAX制作仙人球快速建模的方法,有需要的小伙伴们快和小编一起来看看3dmax软件建模带刺的仙人球模型的详细步骤与教程吧! 3d ...
- HDU - 2153 仙人球的残影
OJ地址:https://vjudge.net/problem/HDU-2153 在美丽的HDU,有一名大三的同学,他的速度是众所周知的,跑100米仅仅用了2秒47,在他跑步过程中会留下残影的哎,大家 ...
- 【模拟】仙人球的残影
描述 在美丽的TZC,有一名大三的同学,他的速度是众所周知的,跑100米仅仅用了2秒47,在他跑步过程中会留下残影的哎,大家很想知道他是谁了吧,他叫仙人球,既然名字这样了,于是他的思想是单一的,他总是 ...
- 仙人球模型matlab,数字人C4D建模课堂之十六:仙人球建模
目的: 有上面几节课的知识做基础,这节课简要谈谈仙人球的制作思路,并对难点做解释.感兴趣的朋友可以自己尝试制作,有问题,到C4D吧询问,共同研究. 1.如何制作仙人球体 因为还要细分,所以尽量减少分段 ...
- 花卉世界大观园和杂技之游
最近的周末一直在忙,总算抽出来了一个周末来,我就计划着和家里人出去玩玩,想了几个路线,最后定格为早上去花卉世界大观园,南四环,离我住的地方不远,下午计划去朝阳剧院看杂技. 我们赶了个大早进去,就是怕中 ...
- OSChina 周二乱弹 —— 最要命的编程语言?
2019独角兽企业重金招聘Python工程师标准>>> 昨天是周一,没有加班的盆友摸摸你的良心问问,你是不是个合格的程序员? 房间干净有条理的人,找起东西来都像程序员,设好运算模式, ...
- 怎么将算法改成程序_多肉烂根怎么办?将土培改成水培,长势好,叶子变得更水灵...
导语:养多肉的人多但要知道它最害怕就是用太多的水,会让它出现烂根一烂根就会让它直接死掉,每次在给它浇水时都没有一个数也让人担心不已.其实我们还可以把它直接放在水里养殖,不仅长得好还不会烂根,长势好,叶 ...
- 问题战略[置顶] 十八年开发经验分享(四)问题解决篇(下)
最近一直在研究问题战略之类的问题,下午正好有机会和大家分享一下. 关于本系列文字的源来,衷初和内容定位可以考参第一篇的头开部份,链接址地如下: http://blog.csdn.net/binaryt ...
- TensorFlow的新生!
点击"小詹学Python",选择"置顶"公众号 重磅干货,第一时间送达 本文转载自机器之心 TensorFlow 2.0 带来了大量改变.谷歌工程师 Cassi ...
最新文章
- Nginx源码分析-内存池
- 随便说说---java初级学习路线
- Halcon基于形状的几何定位函数说明
- 剑指offer(C++)-JZ55:二叉树的深度(数据结构-树)
- JAVA浮点数浮点数转换成人民币读法
- 应用程式中夜间模式的Android DayNight主题
- eclipse mac oracle数据库,Eclipse连接Oracle数据库的具体步骤
- java编程环境_java开发环境
- CMake 编译静态库和动态库
- 解决WIN10家庭版无法远程桌面连接的问题
- 用ReadyBoost提高Windows 7系统性能
- 用echarts绘制瀑布图
- ES文件浏览器(清理垃圾神器, 强大网盘管理功能, 强大文件分析能力)
- 强大到爆的代码阅读工具understand
- PS作业 不一样的我
- 大学生前端,毕业面试知道这几点,offter拿到手软
- 阿里云计算巢软件免费试用中心正式上线,企业用户可免费试用1个月
- 台式计算机选购,电脑什么配置好 教你如何选购一台好的台式电脑
- Activiti 流程部署方式 activi 动态部署(高级源码篇)
- 爱乐乐iLELE®益生菌新品上市由妈咪爱研究中心出品