题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1494

sol  :前排膜拜http://blog.csdn.net/qpswwww/article/details/45362639

   虽然dalao们说了一些最小表示法啊什么k=5时只有52种状态啊balabala,然而我并不会.......

   因为k很小,可以考虑用状压来记录联通块信息,考虑dp

   dp[i][j]表示前i个点,最后k个点联通情况为j时的方案数

   由于n很大,考虑采用矩阵快速幂优化,用并查集判环&维护

   那么最终可以构造函数f[x][y]表示状态x向状态y转移有多少种合法的连接方式

   初始函数g[x]是一个行向量,每个位置代表一个初始状态

   这样就可以做了........最后输出A[1][1]即可

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int Mx=;
const int p=;
using namespace std;
ll n;
int K,tot/*状态总数*/,Tr_siz[]={,,,,,}/*完全图的生成树个数*/;
int fa[Mx],siz[Mx]/*第i个联通块的大小*/,status[],hash[<<]/*hash[S]=状态S的编号*/; struct Matrix
{
int n,m; ll num[Mx][Mx];
Matrix() { n=m=; memset(num,,sizeof(num)); }
}A,trans;
Matrix operator*(Matrix a,Matrix b)
{
Matrix c;
c.n=a.n,c.m=b.m;
for(int k=;k<=a.m;k++)
for(int i=;i<=c.n;i++)
for(int j=;j<=c.m;j++)
c.num[i][j]=(c.num[i][j]+a.num[i][k]*b.num[k][j]%p)%p;
return c;
}
void Pow(ll c)
{
while(c)
{
if(c&) A=A*trans;
trans=trans*trans;
c>>=;
}
} void dfs(int x,int sta) //当前要加入第x个点的联通状态,当前的状态为sta
{
if(x==K+)
{
memset(siz,,sizeof(siz));
A.num[][++tot]=;
for(int i=;i<=K;i++)
siz[sta>>((i-)*)&]++;
for(int i=;i<K;i++)
A.num[][tot]*=Tr_siz[siz[i]];
status[tot]=sta;
hash[sta]=tot;
return;
}
int tmp=-; //联通块的最大编号,联通块编号的区间是[0,K-1]
for(int i=;i<x;i++) //!!!当前的sta里只保存了1~pos-1这些点的连通性
tmp=max(tmp,sta>>((i-)*)&);
for(int i=;i<=tmp+&&i<K;i++)
dfs(x+,sta<<|i);
} int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
} int Get_Status() //用当前的并查集来求出新的点2到点k+1的最小表示
{
int sta=,tot=;
bool vis[Mx]; memset(vis,false,sizeof(vis));
for(int i=K+;i>=;i--)
if(!vis[i])
{
vis[i]=true,sta|=tot<<((i-)*);
for(int j=i-;j>=;j--)
if(find(i)==find(j))
vis[j]=true,sta|=tot<<((j-)*);
tot++;
}
return hash[sta];
} void cal(int sta,int addsta) //用加边状态addsta去更新最小表示法sta,addsta里的第i位为1表示第k+1个点要和点i+1连新边
{
for(int i=;i<=K+;i++) fa[i]=i;
for(int i=;i<=K;i++) //枚举点对(i,j)是否在最小表示法里的同一联通块内,将最小表示法中的连通性用并查集表示
for(int j=i+;j<=K;j++)
if((status[sta]>>((i-)*)&)==(status[sta]>>((j-)*)&))
{
int rooti=find(i),rootj=find(j);
if(rooti!=rootj) fa[rooti]=rootj;
}
for(int i=;i<=K;i++)
if(addsta&(<<(i-)))
{
int rooti=find(i),rootj=find(K+);
if(rooti==rootj) return; //判环,加的新边的两端点原来就是联通的,加入新边后会出现环
fa[rooti]=rootj;
}
bool flag=false; //flag=true表示有点和点1联通
for(int i=;i<=K+;i++)
if(find(i)==find())
{
flag=true; break;
}
if(!flag) return; //点1不链接后面的点,那么这个生成树不联通
trans.num[sta][Get_Status()]++;
} int main()
{
scanf("%d%lld",&K,&n);
dfs(,); A.n=; A.m=trans.n=trans.m=tot;
for(int i=;i<=tot;i++)
for(int j=;j<(<<K);j++) cal(i,j);
Pow(n-K); printf("%lld\n",A.num[][]);
return ;
}

最新文章

  1. jquery理财贷款计算器
  2. WPF模糊效果(BlurEffect)
  3. C++ CreateThread 实例
  4. Make something people want
  5. java.awt.Robot
  6. 基于Node的PetShop,oauth2认证RESTful API
  7. 关于移动端的font和图片的问题
  8. 20Mybatis_订单商品数据模型_一对一查询——resultType和resultMap两种方式以及两种方式的总结
  9. rsyslog 解决日志截断不读取问题
  10. 四种简单的排序算法的php实现
  11. Linux常用的系统监控shell脚本
  12. PTVS在Visual Studio中的安装
  13. Chrome浏览器读写系统剪切板
  14. node.js爬虫
  15. 树状数组-逆序对-HDU6318
  16. C# xml 读xml、写xml、Xpath、Xml to Linq、xml添加节点 xml修改节点
  17. 初学python之路-day14
  18. 网站图标 favicon.ico
  19. USB基础知识概论(版本:v0.9.2)
  20. [转载] IIS来搭建一个只能实现基本功能的FTP服务器

热门文章

  1. AngularJS常见面试题
  2. selenium破解极限
  3. Redis ----------String的操作
  4. PHP递归操作
  5. java中substring()、charAt()、indexOf() (2013-05-05-bd 写的日志迁移
  6. 理解JAVA与C的运行机制
  7. Maven项目Update Project自动恢复为JRE1.5的问题
  8. 安测云验证有CTA问题
  9. json对象和java对象的相互转换方法(json-lib、jackson、fastjson、gson)
  10. jQuery上传文件控件Uploadify使用