线性代数(矩阵乘法):NOI 2007 生成树计数

  这道题就是深搜矩阵,再快速幂。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <map>
  5 using namespace std;
  6 const int maxn=200;
  7 const int mod=65521;
  8 struct Matrix{
  9     long long mat[maxn][maxn];
 10     int r,c;
 11     Matrix(int r_=0,int c_=0,int on=0){
 12         memset(mat,0,sizeof(mat));
 13         r=r_;c=c_;
 14         if(on)for(int i=1;i<=r;i++)mat[i][i]=1;
 15     }
 16     Matrix operator *(Matrix a){
 17         Matrix ret(r,a.c);
 18         long long l;
 19         for(int i=1;i<=r;i++)
 20             for(int k=1;k<=c;k++){
 21                 l=mat[i][k];
 22                 for(int j=1;j<=a.c;j++)
 23                     (ret.mat[i][j]+=(l*a.mat[k][j])%mod)%=mod;
 24             }
 25         return ret;
 26     }
 27     Matrix operator ^(long long k){
 28         Matrix ret(r,c,1),x(r,c);
 29         for(int i=1;i<=r;i++)
 30             for(int j=1;j<=c;j++)
 31                 x.mat[i][j]=mat[i][j];
 32         while(k){
 33             if(k&1)
 34                 ret=ret*x;
 35             k>>=1;
 36             x=x*x;
 37         }
 38         return ret;
 39     }
 40 }A,B;
 41
 42 long long n;
 43 map<int,int>ID;
 44 map<int,bool>used;
 45 int k,e,e1,E[maxn][2];
 46 int cnt,st[1<<17],mem[1<<17];
 47 int fa[maxn],sz[maxn],vis[maxn];
 48 int Find(int x){
 49     return x==fa[x]?x:fa[x]=Find(fa[x]);
 50 }
 51 bool Check(int s){
 52     for(int i=1;i<maxn;i++)
 53         fa[i]=i,sz[i]=1;
 54     for(int i=0;i<e+e1;i++)
 55         if(s&(1<<i)){
 56             int u=Find(E[i][0]),v=Find(E[i][1]);
 57             if(u!=v){fa[u]=v;sz[v]+=sz[u];}
 58             else return false;
 59         }
 60     return true;
 61 }
 62
 63 void Solve(int x){
 64     for(int i=1;i<=x;i++)
 65         for(int j=i+1;j<=x;j++)
 66             E[e][0]=i,E[e][1]=j,e++;
 67     for(int i=1;i<=x;i++)
 68         E[e+e1][0]=i,E[e+e1][1]=x+1,e1++;
 69
 70     for(int s=(1<<e)-1,num;s>=0;s--)
 71         if(Check(s)){
 72             memset(vis,0,sizeof(vis));num=0;
 73             for(int i=1;i<=x;i++){
 74                 if(vis[Find(i)])continue;
 75                 vis[Find(i)]=++num;
 76             }
 77             num=0;
 78             for(int i=1;i<=x;i++)
 79                 num=num*10+vis[Find(i)];
 80             if(ID[num])B.mat[ID[num]][1]+=1;
 81             else{
 82                 A.r+=1;A.c+=1;B.r+=1;
 83                 B.mat[ID[num]=B.r][1]=1;
 84                 st[++cnt]=s;mem[cnt]=num;
 85             }
 86         }
 87
 88     for(int t=1,s;t<=cnt;t++){
 89         for(int p=(1<<e1)-1,num;p>=0;p--){
 90             s=st[t]^(p<<e);
 91             if(Check(s)&&sz[Find(1)]!=1){
 92                 memset(vis,0,sizeof(vis));num=0;
 93                 for(int i=2;i<=x+1;i++){
 94                     if(vis[Find(i)])continue;
 95                     vis[Find(i)]=++num;
 96                 }
 97                 num=0;
 98                 for(int i=2;i<=x+1;i++)
 99                     num=num*10+vis[Find(i)];
100                 A.mat[ID[num]][ID[mem[t]]]+=1;
101             }
102         }
103     }
104     return;
105 }
106
107 int main(){
108 #ifndef ONLINE_JUDGE
109     freopen("count.in","r",stdin);
110     freopen("count.out","w",stdout);
111 #endif
112     scanf("%d%lld",&k,&n);
113     k=min(1ll*k,n);Solve(k);B.c=1;
114     A=A^((n-k)%(1ll*(mod+1)*(mod-1)));B=A*B;
115     printf("%lld\n",B.mat[1][1]);
116     return 0;
117 }
时间: 2024-10-06 13:25:24

线性代数(矩阵乘法):NOI 2007 生成树计数的相关文章

线性代数——矩阵乘法(续)

之前提到过,矩阵乘法可以视作对向量基底的改变,而基底的选取可能直接导致向量维度的改变.一个2*3矩阵可以把二维向量映射到三维空间,故矩阵可以被视作操控空间的一种手段. 矩阵改变了向量维度 为弄懂这种变换的具体性质,我们必须从矩阵本身开始分析.依照之前的思路,矩阵的各列是基底向量,矩阵的右乘就是对列向量的线性组合,同理,矩阵左乘可以看作是对矩阵行向量的线性组合,所以矩阵的列构成了列空间,行构成了行空间.经线性变换后,若有T(x)=0 亦即 Ax=0, 则称 x 在A的零空间N(A)中. 我们用秩来

线性代数-矩阵-乘法 C和C++实现

矩阵的知识点之多足以写成一本线性代数. 所以我们把矩阵封装成类.以C++为主进行详解. C++语言 分段详解: 基本成员: 矩阵类的成员变量我们使用三个: 矩阵的行数 矩阵的列数 用二维数组(向量)存放矩阵中的所有元素 int m_iRows; int m_iColumns; vector<vector<T>> m_vecMatrix; 矩阵中的基本成员函数包括 加入一行 加入一列 bool addOneRowToBack(vector<T> &vec); //

【BZOJ 4180】 4180: 字符串计数 (SAM+二分+矩阵乘法)

4180: 字符串计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 164  Solved: 75 Description SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999. 他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', 'D'.现在他要求蒟蒻yts1999构造一个新的字符串S,构造的方法是:进行多次操作,每一次操作选择T的一个子串,将其加入S的末尾. 对于一个可构

线性代数——矩阵与矩阵乘法

在刚接触线性代数时,最先学到的是行列式,随之而来的就是矩阵.矩阵的出现过于突兀,当初学习时完全不清楚它的概念,更不要说还有矩阵乘法等各种奇怪的算术操作.于是从网上学习了各种矩阵概念,受益良多,在此总结一下学到的概念. 一.矩阵 矩阵最早来自于方程组的系数及常数所构成的方阵.——百度百科 如此看来,矩阵和行列式还是有联系的,矩阵最初可能就是用来表示行列式用的 方程组 改写成矩阵的形式 然而矩阵的作用不仅限于此,它有着线性变换的作用,我们将通过分析矩阵乘法来详加解释 二.矩阵乘法 提起矩阵乘法,我们

【bzoj4818】[Sdoi2017]序列计数 矩阵乘法

原文地址:http://www.cnblogs.com/GXZlegend/p/6825132.html 题目描述 Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望,这n个数中,至少有一个数是质数.Alice想知道,有多少个序列满足她的要求. 输入 一行三个数,n,m,p. 1<=n<=10^9,1<=m<=2×10^7,1<=p<=100 输出 一行一个数,满足Alice的要求的序列数量,答案对2017

BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法

Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ,这n个数中,至少有一个数是质数.Alice想知道,有多少个序列满足她的要求. Input 一行三个数,n,m,p. 1<=n<=10^9,1<=m<=2×10^7,1<=p<=100 Output 一行一个数,满足Alice的要求的序列数量,答案对20170408取模. Sample Input 3 5 3 Sample Outp

bzoj1494 生成树计数 (dp+矩阵快速幂)

题面欺诈系列... 因为一个点最多只能连到前k个点,所以只有当前的连续k个点的连通情况是对接下来的求解有用的 那么就可以计算k个点的所有连通情况,dfs以下发现k=5的时候有52种. 我们把它们用类似于并查集的方式表达(比如12132代表点1和点3连通,2和5连通,3自己),然后再压缩一下. 但要注意的是,12132和23213这两种实际对应的是一种连通情况,我们只要把它都化成字典序最小的那种就可以了 然后考虑增加一个新点以后状态的转移,可以枚举这个点与前k个点(始状态S)的连边情况,其中有一些

bzoj1002 生成树计数 找规律

这道题第一眼是生成树计数,n是100,是可以用O(n^3)的求基尔霍夫矩阵的n-1阶的子矩阵的行列式求解的,但是题目中并没有说取模之类的话,就不好办了. 用高精度?有分数出现. 用辗转相除的思想,让它不出现分数.但过程中会出现负数,高精度处理负数太麻烦. 用Python打表?好吧,Python还不熟,写不出来..... 所以,如果这道题我考场上遇到,最多用double骗到n<=20的情况的部分分. 最终只能求助于题解了... 好像是通过观察行列式的特点,推导出关于答案f(n)的递推式(f(n)=

【日常学习】codevs1287 矩阵乘法题解

转载请注明出处 [ametake版权所有]http://blog.csdn.net/ametake欢迎来看. 先上题目 题目描述 Description 小明最近在为线性代数而头疼,线性代数确实很抽象(也很无聊),可惜他的老师正在讲这矩阵乘法这一段内容. 当然,小明上课打瞌睡也没问题,但线性代数的习题可是很可怕的.小明希望你来帮他完成这个任务. 现在给你一个ai行aj列的矩阵和一个bi行bj列的矩阵,要你求出他们相乘的积(当然也是矩阵). (输入数据保证aj=bi,不需要判断) 矩阵乘法的定义: