题面欺诈系列...

因为一个点最多只能连到前k个点,所以只有当前的连续k个点的连通情况是对接下来的求解有用的

那么就可以计算k个点的所有连通情况,dfs以下发现k=5的时候有52种。

我们把它们用类似于并查集的方式表达(比如12132代表点1和点3连通,2和5连通,3自己),然后再压缩一下。

但要注意的是,12132和23213这两种实际对应的是一种连通情况,我们只要把它都化成字典序最小的那种就可以了

然后考虑增加一个新点以后状态的转移,可以枚举这个点与前k个点(始状态S)的连边情况,其中有一些是不合法的:

  1.连到了两个本来就连通的点上(导致成环)

  2.在1号点不与其他点连通的情况下,没有连到1号点(导致不连通)

然后再根据连边情况得到终状态E,将trans[S][E]++。最后trans[i][j]表示的就是加入一个点后由i状态到j状态的方案数

那么就可以得到递推式$f[i][j]=\sum^{总状态数}_{k=1}{f[i-1][k]*trans[k][j]}$,其中f[i][j]表示以i为结尾的k个点状态是j的方案数

那么答案就是f[N][1](假设1是都连通的状态)

然后初值就应该是f[K][i]=i状态的方案数,其中i状态的方案数为它其中每个联通块方案数的乘积。

那么联通块的方案数怎么算呢?其实题面已经说了...n个点的方案数就是$n^{n-2)}$

然后就可以愉快地dp一脸啦

容易发现递推的形式其实和矩阵乘法是相同的,把f[i]和trans看作矩阵,就是$f[N]=f[K]*trans^{N-K}$

然后就可以倍增做矩阵快速幂了。方法和整数的快速幂是一样的。

复杂度:

  K=5的状态数接近50,$log(10^{15})$接近50。

  所以基本上是$50^3*50=6250000$的。

代码写的很蛋疼...

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#define LL long long
#define inf 0x3f3f3f3f
using namespace std;
const LL maxn=1e15+,maxs=,p65=,mod=; LL rd(){
LL x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} LL N;int K,sct,num[]={,,,,,};
LL f[maxs];
LL trans[][maxs][maxs],out[][maxs][maxs];
struct ST{
int s[];
ST(int x=){memset(s,x,sizeof(s));}
}sta[maxs];
struct Mat{
LL m[maxs][maxs];
Mat(){memset(m,,sizeof(m));}
};
int mp[p65]; void print(ST s){
for(int i=;i<=K;i++) printf("%d",s.s[i]);
}
int STtoInt(ST s){
int x=;for(int i=;i<=K;i++) x=x*+s.s[i];return x;
} ST toLeast(ST s){
ST flag=ST(-),re=ST();int n=;
for(int i=;i<=K;i++){
if(flag.s[s.s[i]]==-) flag.s[s.s[i]]=n++;
re.s[i]=flag.s[s.s[i]];
}return re;
} void dfs1(int x,ST s,int m){
if(x>=K+){
sta[++sct]=s;mp[STtoInt(s)]=sct;return;
}
for(int i=;i<=m+;i++){
s.s[x]=i;
dfs1(x+,s,max(m,i));
}
} void dfs2(int x,ST s,ST from){
if(x>=K+){
bool flag[],bb=s.s[];ST to=ST();int mi=;
memset(flag,,sizeof(flag));
//print(from);printf("\t");print(s);printf("\n");
for(int i=;i<=K;i++){
if(!s.s[i]) continue;
if(flag[from.s[i]]) return;
flag[from.s[i]]=;mi=min(mi,from.s[i]);
}
for(int i=;i<=K;i++){
to.s[i-]=flag[from.s[i]]?mi:from.s[i];
if(from.s[]==to.s[i-]) bb=;
}to.s[K]=mi;
if(!bb) return;
to=toLeast(to);
//print(from);printf("\t");print(s);printf("\t");print(to);printf("\n");
trans[][mp[STtoInt(from)]][mp[STtoInt(to)]]++; }else{
dfs2(x+,s,from);s.s[x]=;dfs2(x+,s,from);
}
} void sets(){
for(int i=;i<=sct;i++){
dfs2(,ST(),sta[i]);
//for(int j=1;j<=sct;j++) printf("%d ",trans[0][i][j]);printf("\n");
ST cnt=ST();
for(int j=;j<=K;j++) cnt.s[sta[i].s[j]]++;
f[i]=;for(int j=;j<K;j++) if(num[cnt.s[j]])f[i]*=num[cnt.s[j]];
}
} void solve(){
LL p=N-K;bool b=,c=;int i,j,k;
for(i=;i<=sct;i++) out[][i][i]=;
while(p){
if(p&){
memset(out[c],,sizeof(out[c]));
for(i=;i<=sct;i++){
for(j=;j<=sct;j++){
for(k=;k<=sct;k++){
out[c][i][j]=(out[c][i][j]+out[c^][i][k]*trans[b^][k][j])%mod;
}
}
}c^=;
}
memset(trans[b],,sizeof(trans[b]));
for(i=;i<=sct;i++){
for(j=;j<=sct;j++){
for(k=;k<=sct;k++){
trans[b][i][j]=(trans[b][i][j]+trans[b^][i][k]*trans[b^][k][j])%mod;
}
}
}p>>=;b^=;
}LL ans=;
for(i=;i<=sct;i++){
ans=(ans+f[i]*out[c^][i][])%mod;
}printf("%d\n",ans);
} int main(){
int i,j,k;
K=rd(),N=rd();
dfs1(,ST(),);sets();
solve();
return ;
}

bzoj1494 生成树计数 (dp+矩阵快速幂)的更多相关文章

  1. bnuoj 34985 Elegant String DP+矩阵快速幂

    题目链接:http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=34985 We define a kind of strings as elegant s ...

  2. HDU 5434 Peace small elephant 状压dp+矩阵快速幂

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5434 Peace small elephant  Accepts: 38  Submissions: ...

  3. 【BZOJ】2004: [Hnoi2010]Bus 公交线路 状压DP+矩阵快速幂

    [题意]n个点等距排列在长度为n-1的直线上,初始点1~k都有一辆公车,每辆公车都需要一些停靠点,每个点至多只能被一辆公车停靠,且每辆公车相邻两个停靠点的距离至多为p,所有公车最后会停在n-k+1~n ...

  4. 【BZOJ】4861: [Beijing2017]魔法咒语 AC自动机+DP+矩阵快速幂

    [题意]给定n个原串和m个禁忌串,要求用原串集合能拼出的不含禁忌串且长度为L的串的数量.(60%)n,m<=50,L<=100.(40%)原串长度为1或2,L<=10^18. [算法 ...

  5. BZOJ5298 CQOI2018 交错序列 【DP+矩阵快速幂优化】*

    BZOJ5298 CQOI2018 交错序列 [DP+矩阵快速幂优化] Description 我们称一个仅由0.1构成的序列为"交错序列",当且仅当序列中没有相邻的1(可以有相邻 ...

  6. Codeforces 621E Wet Shark and Block【dp + 矩阵快速幂】

    题意: 有b个blocks,每个blocks都有n个相同的0~9的数字,如果从第一个block选1,从第二个block选2,那么就构成12,问对于给定的n,b有多少种构成方案使最后模x的余数为k. 分 ...

  7. codeforces E. Okabe and El Psy Kongroo(dp+矩阵快速幂)

    题目链接:http://codeforces.com/contest/821/problem/E 题意:我们现在位于(0,0)处,目标是走到(K,0)处.每一次我们都可以从(x,y)走到(x+1,y- ...

  8. [BZOJ1009] [HNOI2008] GT考试(KMP+dp+矩阵快速幂)

    [BZOJ1009] [HNOI2008] GT考试(KMP+dp+矩阵快速幂) 题面 阿申准备报名参加GT考试,准考证号为N位数X1X2-.Xn,他不希望准考证号上出现不吉利的数字.他的不吉利数学A ...

  9. 2019.02.11 bzoj4818: [Sdoi2017]序列计数(矩阵快速幂优化dp)

    传送门 题意简述:问有多少长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数,且其中至少有一个数是质数,答案对201704082017040820170408取模(n≤1e9, ...

随机推荐

  1. Luogu P3390 【模板】矩阵快速幂&&P1939 【模板】矩阵加速(数列)

    补一补之前的坑 因为上次关于矩阵的那篇blog写的内容太多太宽泛了,所以这次把一些板子和基本思路理一理 先看这道模板题:P3390 [模板]矩阵快速幂 首先我们知道矩阵乘法满足结合律而不满足交换律的一 ...

  2. [尝鲜]妈妈再也不用担心 dotnet core 程序发布了: .NET Core Global Tools

    什么是 .NET Core Global Tools? Global Tools是.NET Core 2.1 中一个初次出现的特性.Global Tools提供了一种方法,让开发人员编写的.NET C ...

  3. Netdata---Linux系统性能实时监控平台部署记录

    通常来说,作为一个Linux的SA,很有必要掌握一个专门的系统监控工具,以便能随时了解系统资源的占用情况.下面就介绍下一款Linux性能实时监测工具-Netdata,它是Linux系统实时性能监测工具 ...

  4. python基础学习笔记(十一)

    迭代器 本节进行迭代器的讨论.只讨论一个特殊方法---- __iter__  ,这个方法是迭代器规则的基础. 迭代器规则 迭代的意思是重复做一些事很多次---就像在循环中做的那样.__iter__ 方 ...

  5. Python_闭包_27

    #闭包:嵌套函数,内部函数 并且必须调用外部函数的变量 def outer(): a = 1 def inner(): print(a) inner() print(inner.__closure__ ...

  6. 701 C. They Are Everywhere

    链接 [http://codeforces.com/group/1EzrFFyOc0/contest/701/problem/C] 题意 给你一个包含大小写字母长度为n的字符串,让你找包含所有种类字符 ...

  7. 《Linux内核设计与实现》第三章学习笔记

    第三章  进程管理 姓名:王玮怡  学号:20135116 一.进程 1.进程的含义 进程是处于执行期的程序以及相关资源的总称,程序本身并不是进程,实际上就是正在执行的代码的实时结果.Linux内核通 ...

  8. jeecg中vaildfrom的复杂的表单校验

    简介 jeecg生成的页面都是使用validfrom组件来确保数据的完整性和准确性. 凡要验证格式的元素均需绑定datatype属性,datatype可选值内置有10类,用来指定不同的验证格式. 如果 ...

  9. git体会

    刘仙臣个人github链接:http://www.github.com/liuxianchen 这次作业学会了关于git的一些基本操作,学习了到了许多东西,为以后的学习奠定了基础,激发了学习的兴趣.具 ...

  10. I/O(输入/输出)

    1.创建引用ObjectInputStream ois =null; ObjectOutputStream oos = null; ByteArrayInputStream bais = null; ...