HDU_Steps8.3 矩阵应用 HDU1575 HDU1757 HDU2294 HDU2254 HDU2276 HDU2855 HDU3519 HDU3509

来源:互联网 发布:淘宝大码女装微胖 编辑:程序博客网 时间:2024/06/06 00:40

STEPS8.3一些矩阵的应用,还是比较难的

HDU1575 Tr A

矩阵相乘基础题

HDU1757 A Simple Math Problem

7.2中的题目,重复了,构造矩阵

HDU2294 Pendant

f[i][j]代表j种颜色组成i个珠子,有方程f[i][j]=f[i-1][j]*j+f[i-1][j-1]*(k-j-1),但由于N较大采用一般的方法DP必然按会超时的。考虑构造矩阵f[i]=A*f[i-1],然后允许的长度是k~n,所以ans=(A^k+....+A^n)*f[0],初始只有f[0][0]=1,其它都是0.所以答案是矩阵种的a[k][0]

#include<cstdio>#include<string.h>using namespace std;int cas,n,k;const int MOD=1234567891;typedef long long LL;struct mat{int a[31][31];mat(int type){memset(a,0,sizeof a);if(type==1){for(int i=0;i<=k;i++){a[i][i]=i;if(i>0)a[i][i-1]=k-i+1;}}}mat mult(mat b){//矩阵加法mat c(0);for(int i=0;i<=k;i++)for(int j=0;j<=k;j++)for(int l=0;l<=k;l++)c.a[i][j]=((LL)c.a[i][j]+(LL)a[i][l]*(LL)b.a[l][j])%MOD;return c;}mat add(mat b){//矩阵乘法mat c(0);for(int i=0;i<=k;i++)for(int j=0;j<=k;j++)c.a[i][j]=((LL)a[i][j]+(LL)b.a[i][j])%MOD;return c;}};//二分计算A^kmat binMat(int k){if(k<=1)return mat(k);mat m=binMat(k/2);m=m.mult(m);if(k&1)m=m.mult(mat(1));return m;}//二分计算A^l+...A^rmat cal(int l,int r){if(l==r)return binMat(l);int m=(l+r+1)/2;mat t=cal(l,m-1);//算前一半的和mat t2=binMat(m-l);//中介的矩阵t=t.add(t2.mult(t));if((r-l+1)&1)t=t.add(binMat(r));//如果是奇数,则加上最后一个return t;}int main(){scanf("%d",&cas);while(cas--){scanf("%d%d",&n,&k);printf("%d\n",cal(k,n).a[k][0]);}return 0;}

HDU2254 奥运

路径条数,只要把邻接矩阵乘起来就可以了。数据比较小,先打表,再再表中直接取就行了

#include<cstdio>#include<map>#include<string.h>using namespace std;int cas,n,v1,v2,t1,t2,ta,tb,ncity;int m[32][32];//标记初始矩阵map<int,int> mmap;struct jz{int a[32][32];jz(){}jz(int type){if(type==0)memset(a,0,sizeof a);if(type==1){for(int i=1;i<=ncity;i++)for(int j=1;j<=ncity;j++)a[i][j]=m[i][j];}}jz mult(jz jb){jz jc(0);for(int i=1;i<=ncity;i++){for(int j=1;j<=ncity;j++){for(int k=1;k<=ncity;k++){jc.a[i][j]=(jc.a[i][j]+a[i][k]*jb.a[k][j])%2008;}}}return jc;}}M[10001];int main(){while(scanf("%d",&n)!=EOF){mmap.clear();memset(m,0,sizeof m);ncity=1;for(int i=1;i<=n;i++){scanf("%d%d",&ta,&tb);if(mmap.count(ta)==0)mmap[ta]=ncity++;if(mmap.count(tb)==0)mmap[tb]=ncity++;m[mmap[ta]][mmap[tb]]++;}memcpy(M[0].a,m,sizeof m);for(int i=1;i<=10000;i++)M[i]=M[i-1].mult(jz(1));scanf("%d",&n);while(n--){int ans=0;scanf("%d%d%d%d",&v1,&v2,&t1,&t2);if(mmap.count(v1)==0||mmap.count(v2)==0){ans=0;}else{for(int i=t1-1;i<t2;i++){ans=(ans+M[i].a[mmap[v1]][mmap[v2]])%2008;}}printf("%d\n",ans);}}return 0;}


HDU2276 Kiki & Little Kiki 2

构造矩阵,第i个灯的状态d[i],以及它左边的灯的状态d[i-1],则下一秒d[i]=(d[i]+d[i-1])/2,一共就4种情况01,10,00,10,模拟一下就可以验证方程的正确性了,然后利用矩阵可以再logN内得到第N秒的状态,注意这里不能用递归二分矩阵,会暴栈

#include<cstdio>#include<string.h>using namespace std;int n,m;char s[105];struct jz{int a[101][101];jz(int type){memset(a,0,sizeof a);if(type==1){for(int i=1;i<=n;i++){a[i][i==1?n:i-1]=a[i][i]=1;}}if(type==2){//单位矩阵for(int i=1;i<=n;i++)a[i][i]=1;}}jz mult(jz b){jz c(0);for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){for(int k=1;k<=n;k++){c.a[i][j]=(c.a[i][j]+a[i][k]*b.a[k][j]);}c.a[i][j]%=2;//模操作是很占时间的!!}}return c;}};void outres(jz jj){int rs[105];memset(rs,0,sizeof rs);for(int i=1;i<=n;i++){for(int k=1;k<=n;k++){rs[i]=rs[i]+jj.a[i][k]*(s[k-1]-'0');}rs[i]%=2;}for(int i=1;i<=n;i++)printf("%d",rs[i]);printf("\n");}//二分矩阵的非递归写法jz binMat(int k){jz tmp(2),m(1); while(k){if(k&1)tmp=tmp.mult(m);m=m.mult(m);k=k>>1;}return tmp;}int main(){while(scanf("%d",&m)!=EOF){scanf("%s",s);n=strlen(s);jz r=binMat(m);outres(r);}return 0;}

HDU2855 Fibonacci Check-up 

求sigma(c(n,k)*F(k)),其中F是Fibo数列,很容易想到用牛顿二项式展开,Fibo数列可以表示乘A^k*[f0,f1]

#include<cstdio>#include<string.h>using namespace std;int cas,n,m;/*(|1 0| + |0 1|)^n * |0 1|   |1 1| * */struct jz{int a[3][3];jz(int type){memset(a,0,sizeof a);if(type==1){a[1][1]=a[2][1]=a[1][2]=1;a[2][2]=2;}}jz mult(jz b){jz c(0);c.a[1][1]=(a[1][1]*b.a[1][1]+a[1][2]*b.a[2][1])%m;c.a[1][2]=(a[1][1]*b.a[1][2]+a[1][2]*b.a[2][2])%m;c.a[2][1]=(a[2][1]*b.a[1][1]+a[2][2]*b.a[2][1])%m;c.a[2][2]=(a[2][1]*b.a[1][2]+a[2][2]*b.a[2][2])%m;return c;}};jz binmat(int k){if(k<=1)return jz(k);jz r=binmat(k/2);r=r.mult(r);if(k&1)r=r.mult(jz(1));return r;}int main(){scanf("%d",&cas);while(cas--){scanf("%d%d",&n,&m);if(n<=1)printf("%d\n",n);else{jz r=binmat(n);printf("%d\n",r.a[1][2]);}}return 0;}

HDU3519 Lucky Coins Sequence

一串硬币,至少有三个连续面相同的硬币的摆法有多少种,具体的解见注释

#include<cstdio>#include<string.h>using namespace std;/* d[i]代表合法的个数 * f[i][2]代表末两位相同 * f[i][1]代表末两位不同 * d[i]=2*d[i-1]+f[i-1][2]   合法的加上 正反 都依然合法,或者末两位相同再加上一个相同的也会合法 * f[i][2]=f[i-1][1]   末两位不同加上与末位相同的可以使其末两位相同 * f[i][1]=f[i-1][2]+f[i-1][1] 末两位相同或者不同 加上一个与末位不同的 都可以使其成为末两位不同的 * 构造矩阵求解 *  | 2 1 0 |   |d[i-1]   | |d[i]   | *  | 0 0 1 | * |f[i-1][2]|=|f[i][2]| *  | 0 1 1 |   |f[i-1][1]| |f[i][1]| */struct mat{int a[4][4];mat(int type){memset(a,0,sizeof a);if(type==1){a[1][1]=2;a[1][2]=a[2][3]=a[3][2]=a[3][3]=1;}}mat mult(mat m){mat r(0);for(int i=1;i<=3;i++){for(int j=1;j<=3;j++){for(int k=1;k<=3;k++){r.a[i][j]=(r.a[i][j]+a[i][k]*m.a[k][j])%10007;}}}return r;}};mat binMat(int k){if(k<=1)return mat(k);mat m=binMat(k/2);m=m.mult(m);if(k&1)m=m.mult(mat(1));return m;}int main(){int n;while(scanf("%d",&n)!=EOF){if(n<=2){printf("0\n");continue;}mat r=binMat(n-2);printf("%d\n",(2*r.a[1][2]+2*r.a[1][3])%10007);}return 0;}


HDU3509 Buge's Fibonacci Number Problem

给出 F1=f1,F2=f2,Fn=aFn-1+bFn-2

求sigma(Fi^k)..i=1~n (n<1e10,k<50)

很麻烦的一道题目,思想还是用牛顿二项式构造矩阵求解

#include<cstdio>#include<string.h>using namespace std;typedef long long LL;int cas,f1,f2,a,b,n,m,k;int c[55][55],mpa[55],mpb[55],mpf1[55],mpf2[55];int s1,s2;/*这题要注意模的问题,一不小心就会越界 *展开二项式,构造矩阵 * 比如当k=3时,a=b=1时,矩阵如下 * | 0 0 0 1 0 | |    f1^k    | |   f2^k     | * | 0 0 1 1 0 | | f2*f1^(k-1)| | f3*f2^(k-1)| * | 0 1 2 1 0 |×|    ..      |=|    ..      | * | 1 3 3 1 0 | |    f2^k    | |   f3^k     | * | 1 3 3 1 1 | |     s2     | |    s3      | */ void init(){//初始化系数数组,二项式,以及a^n,b^n,以及前两相和//系数c[1][1]=1;c[2][1]=c[2][2]=1;for(int i=3;i<=54;i++){c[i][1]=c[i][i]=1;for(int j=2;j<=i-1;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%m;}//a,b的幂mpa[0]=mpb[0]=1;for(int i=1;i<=54;i++){mpa[i]=((LL)mpa[i-1]*(LL)a)%m;mpb[i]=((LL)mpb[i-1]*(LL)b)%m;}//f1,f2的幂mpf1[0]=mpf2[0]=1;for(int i=1;i<=54;i++){mpf1[i]=((LL)mpf1[i-1]*(LL)f1)%m;mpf2[i]=((LL)mpf2[i-1]*(LL)f2)%m;}//前两项s1=mpf1[k];s2=(mpf2[k]+mpf1[k])%m;}struct mat{int a[55][55];mat(int type){memset(a,0,sizeof a);if(type==1){a[k+1][k+1]=1;for(int i=0;i<=k+1;i++)for(int j=k,jj=0;j>=k-i;j--,jj++)if(i!=k+1)a[i][j]=(((LL)c[i+1][jj+1]*(LL)mpa[i-jj])%m*(LL)mpb[jj])%m;else a[i][j]=a[i-1][j];}}mat mult(mat b){mat c(0);for(int i=0;i<=k+1;i++)for(int j=0;j<=k+1;j++)for(int l=0;l<=k+1;l++)c.a[i][j]=(c.a[i][j]+((LL)a[i][l]*(LL)b.a[l][j])%m)%m;return c;}int sn(){int res=0;for(int i=0;i<=k;i++){res=(res+(((LL)a[k+1][i]*(LL)mpf1[k-i])%m*(LL)mpf2[i])%m)%m;}res=(res+((LL)a[k+1][k+1]*(LL)s2)%m)%m;return res;}};mat binMat(int x){if(x<=1)return mat(x);mat r=binMat(x/2);r=r.mult(r);if(x&1)r=r.mult(mat(1));return r;}int main(){scanf("%d",&cas);while(cas--){scanf("%d%d%d%d%d%d%d",&f1,&f2,&a,&b,&k,&n,&m);init();if(n==1)printf("%d\n",s1);else if(n==2)printf("%d\n",s2);else{mat r=binMat(n-2);printf("%d\n",r.sn());}}}