zoukankan      html  css  js  c++  java
  • bzoj1494 生成树计数 (dp+矩阵快速幂)

    题面欺诈系列...

    因为一个点最多只能连到前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$的。

    代码写的很蛋疼...

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<map>
      5 #include<vector>
      6 #define LL long long 
      7 #define inf 0x3f3f3f3f
      8 using namespace std;
      9 const LL maxn=1e15+5,maxs=55,p65=50000,mod=65521;
     10 
     11 LL rd(){
     12     LL x=0;char c=getchar();int neg=1;
     13     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
     14     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
     15     return x*neg;
     16 }
     17 
     18 LL N;int K,sct,num[6]={0,1,1,3,16,125};
     19 LL f[maxs];
     20 LL trans[2][maxs][maxs],out[2][maxs][maxs];
     21 struct ST{
     22     int s[6];
     23     ST(int x=0){memset(s,x,sizeof(s));}
     24 }sta[maxs];
     25 struct Mat{
     26     LL m[maxs][maxs];
     27     Mat(){memset(m,0,sizeof(m));}
     28 };
     29 int mp[p65];
     30 
     31 void print(ST s){
     32     for(int i=1;i<=K;i++) printf("%d",s.s[i]);
     33 }
     34 int STtoInt(ST s){
     35     int x=0;for(int i=1;i<=K;i++) x=x*6+s.s[i];return x;
     36 }
     37 
     38 ST toLeast(ST s){
     39     ST flag=ST(-1),re=ST();int n=0;
     40     for(int i=1;i<=K;i++){
     41         if(flag.s[s.s[i]]==-1) flag.s[s.s[i]]=n++;
     42         re.s[i]=flag.s[s.s[i]];
     43     }return re;
     44 }
     45 
     46 void dfs1(int x,ST s,int m){
     47     if(x>=K+1){
     48         sta[++sct]=s;mp[STtoInt(s)]=sct;return;
     49     }
     50     for(int i=0;i<=m+1;i++){
     51         s.s[x]=i;
     52         dfs1(x+1,s,max(m,i));
     53     }
     54 }
     55 
     56 void dfs2(int x,ST s,ST from){
     57     if(x>=K+1){
     58         bool flag[6],bb=s.s[1];ST to=ST();int mi=5;
     59         memset(flag,0,sizeof(flag));
     60         //print(from);printf("	");print(s);printf("
    ");
     61         for(int i=1;i<=K;i++){
     62             if(!s.s[i]) continue;
     63             if(flag[from.s[i]]) return;
     64             flag[from.s[i]]=1;mi=min(mi,from.s[i]);
     65         }
     66         for(int i=2;i<=K;i++){
     67             to.s[i-1]=flag[from.s[i]]?mi:from.s[i];
     68             if(from.s[1]==to.s[i-1]) bb=1;
     69         }to.s[K]=mi;
     70         if(!bb) return;
     71         to=toLeast(to);
     72         //print(from);printf("	");print(s);printf("	");print(to);printf("
    ");
     73         trans[0][mp[STtoInt(from)]][mp[STtoInt(to)]]++;
     74         
     75     }else{
     76         dfs2(x+1,s,from);s.s[x]=1;dfs2(x+1,s,from);
     77     }
     78 }
     79 
     80 void sets(){
     81     for(int i=1;i<=sct;i++){
     82         dfs2(1,ST(),sta[i]);
     83         //for(int j=1;j<=sct;j++) printf("%d ",trans[0][i][j]);printf("
    ");
     84         ST cnt=ST();
     85         for(int j=1;j<=K;j++) cnt.s[sta[i].s[j]]++;
     86         f[i]=1;for(int j=0;j<K;j++) if(num[cnt.s[j]])f[i]*=num[cnt.s[j]];
     87     }
     88 }
     89 
     90 void solve(){
     91     LL p=N-K;bool b=1,c=1;int i,j,k;
     92     for(i=1;i<=sct;i++) out[0][i][i]=1;
     93     while(p){
     94         if(p&1){
     95             memset(out[c],0,sizeof(out[c]));
     96             for(i=1;i<=sct;i++){
     97                 for(j=1;j<=sct;j++){
     98                     for(k=1;k<=sct;k++){
     99                         out[c][i][j]=(out[c][i][j]+out[c^1][i][k]*trans[b^1][k][j])%mod;
    100                     }
    101                 }
    102             }c^=1;
    103         }
    104         memset(trans[b],0,sizeof(trans[b]));
    105         for(i=1;i<=sct;i++){
    106             for(j=1;j<=sct;j++){
    107                 for(k=1;k<=sct;k++){
    108                     trans[b][i][j]=(trans[b][i][j]+trans[b^1][i][k]*trans[b^1][k][j])%mod;
    109                 }
    110             }
    111         }p>>=1;b^=1;
    112     }LL ans=0;
    113     for(i=1;i<=sct;i++){
    114         ans=(ans+f[i]*out[c^1][i][1])%mod;
    115     }printf("%d
    ",ans);
    116 }
    117 
    118 int main(){
    119     int i,j,k;
    120     K=rd(),N=rd();
    121     dfs1(2,ST(),0);sets();
    122     solve();
    123     return 0;
    124 }
  • 相关阅读:
    how to write a paper
    attention mechanism思考
    OSX-KVM 安装备忘指南: 在KVM虚拟机中运行macOSX Big Sur / Catalina
    Unity CacheServer6.x版本 安装配置说明
    Linux常用命令2
    Ubuntu 18.04 + apache2.4 配置https证书(SSL)笔记
    Linux常用命令随笔
    软件测试-8 集成测试
    软件测试-7 在实际测试时的一些想法
    软件测试-6 白盒测试
  • 原文地址:https://www.cnblogs.com/Ressed/p/9461115.html
Copyright © 2011-2022 走看看