zoukankan      html  css  js  c++  java
  • [NOI2013]矩阵游戏

    [NOI2013]矩阵游戏


    此题解法大约两种,矩阵乘法和推式子

    都说一下

    矩阵乘法

    构造一下矩阵

    [egin{bmatrix} F[i][j] & 1 \ 0 & 0 end{bmatrix} imes egin{bmatrix} a & 0 \ b & 1 end{bmatrix} = egin{bmatrix} F[i][j+1] & 1 \ 0 & 0 end{bmatrix} ]

    [egin{bmatrix} F[i][m] & 1 \ 0 & 0 end{bmatrix} imes egin{bmatrix} c & 0 \ d & 1 end{bmatrix} = egin{bmatrix} F[i+1][1] & 1 \ 0 & 0 end{bmatrix} ]

    (egin{bmatrix}a & 0 \b & 1end{bmatrix})称为(A),(egin{bmatrix}c & 0 \d & 1end{bmatrix})称作(B)

    答案就是(egin{bmatrix}1 & 1 \0 & 0end{bmatrix} imes A^{n(m-1)} imes B^{n-1})这个矩阵的左上角元素

    搭配十进制快速幂可获得80~100不等的分数

    然后一些dalao发现元素会有循环,若a=1,循环节为1e9+7,否则为1e9+6

    循环节在每行,每列都会循环,所以n,m取模即可

    妥妥的AC

    // It is made by XZZ
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define il inline
    #define rg register
    #define vd void
    #define sta static
    #define int long long
    #define mod 1000000007
    il int gi(){
        rg int x=0,f=1;rg char ch=getchar();
        while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    struct yyb{
        int a,b,c,d;
        yyb(int _a=1,int _b=0,int _c=0,int _d=1){a=_a%mod,b=_b%mod,c=_c%mod,d=_d%mod;}
    };
    yyb operator *(const yyb&a,const yyb&b){
        return (yyb){
            a.a*b.a+a.b*b.c, a.a*b.b+a.b*b.d,
            a.c*b.a+a.d*b.c, a.c*b.b+a.d*b.d
        };
    }
    char N[1000100],M[1000100];
    int a,b,c,d,lenn,lenm,n,m;
    yyb operator ^(yyb a,int b){
        yyb ret;
        while(b){
            if(b&1)ret=ret*a;
            a=a*a;b>>=1;
        }
        return ret;
    }
    main(){
        scanf("%s%s%lld%lld%lld%lld",N+1,M+1,&a,&b,&c,&d);
        lenn=strlen(N+1),lenm=strlen(M+1);
        if(a!=1){
            for(rg int i=1;N[i];++i)n=(n*10+N[i]-'0')%(mod-1);
            for(rg int i=1;M[i];++i)m=(m*10+M[i]-'0')%(mod-1);
            if(!n)n=mod-1;if(!m)m=mod-1;
        }else{
            for(rg int i=1;N[i];++i)n=(n*10+N[i]-'0')%mod;
            for(rg int i=1;M[i];++i)m=(m*10+M[i]-'0')%mod;
            if(!n)n=mod;if(!m)m=mod;
        }
        yyb S=(yyb){1,1,0,0},A=(yyb){a,0,b,1},B=(yyb){c,0,d,1};
        A=(((A^(m-1))*B)^(n-1))*(A^(m-1));
        printf("%lld
    ",(S*A).a);
        return 0;
    }
    

    暴力推式子

    考虑从(F[i][1])(F[i+1][1])的变化。

    这个和随稽数生成器那题有点像(那道题保证互质就能用这个方法AC了)

    (a e 1:)

    (F[i][m]=a^{m-1}F[i][1]+b(a^0+a^1+cdotcdotcdot+a^{m-2})=a^{m-1}F[i][1]+b imesfrac{a^{m-1}}{a-1})

    (F[i+1][1]=a^{m-1} imes c imes F[i][1]+b imes c imesfrac{a^{m-1}}{a-1}+d)

    (p=a^{m-1} imes c,q=b imes c imesfrac{a^{m-1}}{a-1}+d)

    可以发现(F[i+1][1]=p imes F[i][1]+q)

    (a = 1:)

    (F[i][m]=F[i][1]+b(m-1))

    (F[i+1][1]=c imes F[i][1]+b(m-1) imes c+d)

    这时的(p=c,q=b(m-1) imes c+d)

    再按上述方法推一次可算出(F[n+1][1])

    减d除c即可得到答案

    n和m好像也可以按矩阵的方法取模。。然后蜜汁85

    贴上吧:

    // It is made by XZZ
    #include<cstdio>
    #include<algorithm>
    #define il inline
    #define rg register
    #define vd void
    #define sta static
    #define int long long
    #define mod 1000000007
    il int gi(){
    	rg int x=0,f=1;rg char ch=getchar();
    	while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    il int pow(int x,int y){
    	int ret=1;
    	while(y){
    		if(y&1)ret=ret*x%mod;
    		x=x*x%mod;y>>=1;
    	}
    	return ret;
    }
    char nn[1000001],mm[1000001];
    int n,m,a,b,c,d;
    main(){
    	freopen("matrix.in","r",stdin);
    	freopen("matrix.out","w",stdout);
    	scanf("%s%s",nn+1,mm+1);
    	for(rg int i=1;nn[i];++i)n=(n*10+nn[i]-'0')%(mod-1);
    	for(rg int i=1;mm[i];++i)m=(m*10+mm[i]-'0')%(mod-1);
    	a=gi(),b=gi(),c=gi(),d=gi();
    	int A,B,ans;
    	if(a==1)A=c,B=(b*c%mod*(m-1)%mod+d)%mod;
    	else{
    		int p=pow(a,m-1);
    		A=p*c%mod,B=(b*c%mod*(p-1)%mod*pow(a-1,mod-2)%mod+d)%mod;		
    	}
    	if(A==1)ans=(1+B*n)%mod;
    	else{
    		int p=pow(A,n);
    		ans=(p+B*(p-1)%mod*pow(A-1,mod-2)%mod)%mod;
    	}
    	printf("%lld
    ",(ans-d+mod)%mod*pow(c,mod-2)%mod);
    	return 0;
    }
    
  • 相关阅读:
    delphi新语法之泛型实现的对象池模板
    java输入函数
    OC----简单的购物系统----
    关于在堆区创建字符串的疑惑
    自己在OC考试中的试题
    nonatomic, retain,weak,strong用法详解
    python 读写文件和设置文件的字符编码
    python 逐行读取文件的三种方法
    Javascript写入txt和读取txt文件示例
    Javascript的io操作
  • 原文地址:https://www.cnblogs.com/xzz_233/p/8472724.html
Copyright © 2011-2022 走看看