【bzoj3240 && 洛谷P1397】矩阵游戏[NOI2013](矩阵乘法+卡常)

  题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3240

  这道题其实有普通快速幂+费马小定理的解法……然而我太弱了,一开始只想到了矩阵乘法的方法。

  首先定义两个矩阵:

  $ A_{1} = \begin{bmatrix} a & b \\ 0 & 1 \end{bmatrix} $
  $ A_{2} = \begin{bmatrix} c & d \\ 0 & 1 \end{bmatrix} $

  于是我们就可以得到这样的式子:

  $ \begin{aligned}  \begin{bmatrix} f_{n,m} \\ 1 \end{bmatrix} & = A_{1} \begin{bmatrix} f_{n,m-1} \\ 1 \end{bmatrix} \\ & = A_{1}^{m-1} \begin{bmatrix} f_{n,1} \\ 1 \end{bmatrix} \\ & = A_{1}^{m-1} A_{2}\begin{bmatrix} f_{n-1,m} \\ 1 \end{bmatrix} \\ & = ( A_{1}^{m-1}  A_{2} )^{n-1} \begin{bmatrix} f_{1,m} \\ 1 \end{bmatrix} \\ & = ( A_{1}^{m-1} A_{2} )^{n-1}  A_{1}^{m-1} \begin{bmatrix} f_{1,1} \\ 1 \end{bmatrix}  \end{aligned} $

  然后用一发10进制矩阵快速幂能解决这道题了。

  然而……这种做法跑的极慢。在洛谷上还能以近2000msAC,放到bzoj的6元cpu上跑就有些力不从心了,,所以得卡常数。

  经过了十几次提交,使用了奥义·卡常数:10^18进制进制快速幂+循环展开+register后终于卡进了时限。。。

  代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define inf 0x3f3f3f3f
#define mod 1000000007
#define base 1000000000000000000ll
#define eps 1e-18
inline ll read()
{
    ll tmp=0; char c=getchar(),f=1;
    for(;c<‘0‘||‘9‘<c;c=getchar())if(c==‘-‘)f=-1;
    for(;‘0‘<=c&&c<=‘9‘;c=getchar())tmp=tmp*10+c-‘0‘;
    return tmp*f;
}
using namespace std;
struct mat{
    ll num[2][2];
}mat1,mat2;
struct hp{
    ll num[1000010];
    int len;
}n,m;
char s[1000010],t[1000010];
ll a,b,c,d;
mat times(mat a,mat b)
{
    mat c;
    c.num[0][0]=(a.num[0][0]*b.num[0][0]+a.num[0][1]*b.num[1][0])%mod;
    c.num[0][1]=(a.num[0][0]*b.num[0][1]+a.num[0][1]*b.num[1][1])%mod;
    c.num[1][0]=(a.num[1][0]*b.num[0][0]+a.num[1][1]*b.num[1][0])%mod;
    c.num[1][1]=(a.num[1][0]*b.num[0][1]+a.num[1][1]*b.num[1][1])%mod;
    return c;
}
mat power_num(mat a,ll b)
{
    mat ans; ans.num[0][0]=ans.num[1][1]=1; ans.num[0][1]=ans.num[1][0]=0;
    while(b){
        if(b&1)ans=times(ans,a);
        a=times(a,a); b>>=1;
    }
    return ans;
}
mat power(mat a,hp b)
{
    mat ans; ans.num[0][0]=ans.num[1][1]=1; ans.num[0][1]=ans.num[1][0]=0;
    for(register int i=1;i<=b.len;i++){
        ans=times(ans,power_num(a,b.num[i]));
        a=power_num(a,base);
    }
    return ans;
}
int main()
{
    register int i;
    scanf("%s",s); scanf("%s",t); a=read(); b=read(); c=read(); d=read();
    mat1.num[0][0]=a; mat1.num[0][1]=b; mat1.num[1][0]=0; mat1.num[1][1]=1;
    mat2.num[0][0]=c; mat2.num[0][1]=d; mat2.num[1][0]=0; mat2.num[1][1]=1;
    int len1=strlen(s),len2=strlen(t);
    for(i=1;i*18<=len1;i++){
        n.num[i]=0;
        for(register short j=18;j;j--)
            n.num[i]=n.num[i]*10+s[len1-(i-1)*18-j]-‘0‘;
    }
    n.len=len1/18;
    if(len1%18){
        n.num[++n.len]=0;
        for(register short j=0;j<len1%18;j++)n.num[n.len]=n.num[n.len]*10+s[j]-‘0‘;
    }
    for(i=1;i*18<=len2;i++){
        m.num[i]=0;
        for(register short j=18;j;j--)
            m.num[i]=m.num[i]*10+t[len2-(i-1)*18-j]-‘0‘;
    }
    m.len=len2/18;
    if(len1%18){
        m.num[++m.len]=0;
        for(register short j=0;j<len2%18;j++)m.num[m.len]=m.num[m.len]*10+t[j]-‘0‘;
    }
    n.num[1]-=1;
    for(i=1;i<=n.len;i++)if(n.num[i]<0)n.num[i]+=base,n.num[i+1]-=1;
    if(n.num[n.len]==0&&n.len>1)--n.len;
    m.num[1]-=1;
    for(i=1;i<=m.len;i++)if(m.num[i]<0)m.num[i]+=base,m.num[i+1]-=1;
    if(m.num[m.len]==0&&m.len>1)--m.len;
    mat hang=power(mat1,m);
    mat ans=times(power(times(hang,mat2),n),hang);
    printf("%lld\n",(ans.num[0][0]+ans.num[0][1])%mod);
}

bzoj3240

  下次补个快速幂+费马小定理的解法。。。

原文地址:https://www.cnblogs.com/quzhizhou/p/8521667.html

时间: 2024-09-29 08:28:58

【bzoj3240 && 洛谷P1397】矩阵游戏[NOI2013](矩阵乘法+卡常)的相关文章

洛谷P1199 三国游戏 博弈论 数学

洛谷P1199 三国游戏博弈论 数学 这道题 其实 人是必胜的 能取到的最大值 为 每行第二大值中的最大值 为什么呢 假使第一次我们取到了我们心中的那个答案的所在行 那么接着电脑会取 这一行最大值的对应行 那么我们来分析一下电脑取的那个数在他取的那行的特点 首先我们假设其不是最大值,因为矩阵中任意两个数不相同 所以也就是说还有个数比他大,然后就是说电脑取的第二大或者第n大值就已经比我们取的第一大值要大了,说明我们取的行并不是每行第二大值中的最大值所在的行2.也就是说这个数必定为该行中的最大值 那

洛谷P1080 国王游戏 高精度 贪心 数学推公式

洛谷P1080 国王游戏        数学推公式      高精度    贪心 然而这并不是我打出来的,抄题解... 将左手与右手的乘积从小到大排序,然后计算求最大值即可.(需要高精度) 证明: 1)知道,如果相邻的两个人交换位置,只会影响到这两个人的值,不会影响他人 2)假设相邻的两个人i, i + 1.设A[i] B[i] <= A[i + 1] B[i + 1],i之前所有人的左手乘积为S. 则,ans1 = max{S / B[i], S * A[i] / B[i + 1]} 若交换

【不可能的任务24/200】洛谷1640 bzoj1854游戏 匈牙利就是又短又快

bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个“大牛分站”,就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类似于匈牙利(⊙o⊙) (匈牙利的复杂度惊人,1e6秒过) 1 #include <cstdio> 2 bool b[3000001]; 3 int c[3000001],fir[3000001],to[3000001],nex[3000001]; 4 int N,n,p,q; 5 void add(int p,int

洛谷1558 色板游戏 线段树

我先立个Flag 我,这几天,要过1W道线段树题. 题目背景 阿宝上学了,今天老师拿来了一块很长的涂色板. 题目描述 色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格.并从左到右标记为1, 2, ... L.现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事:1. "C A B C" 指在A到 B 号方格中涂上颜色 C.2. "P A B" 指老师的提问:A到 B号方格中有几种颜色.学校的颜料盒中一共有 T 种颜料.为简便起见,我

洛谷 P3390 【模板】矩阵快速幂

这题的确是个模板 但也要提到有关矩乘的内容: 首先什么是矩阵? 给一个线性变换 F(x)   (她可能就是个函数,定义域为向量集) 她可以把一个N维向量变成M维 那么显然x的每一维都可能影响着F(x)的每一维,于是F(x)这个线性变换就应该是N*M个在每两维间的小映射构成的. 于是我们可以把她写成M行N列的矩阵(M行N列是出于习惯) 所以矩阵是用于形象的表示线性变换的工具: 所以怎么合乎习惯的构造矩阵呢? 举例说明: 如,有一个三元组(3维向量)x{a,b,c} 定义F(x)={a+b,b+c}

矩阵乘法 洛谷 P3390【模板】矩阵快速幂

P3390 [模板]矩阵快速幂 题目背景 矩阵快速幂 题目描述 给定n*n的矩阵A,求A^k 输入输出格式 输入格式: 第一行,n,k 第2至n+1行,每行n个数,第i+1行第j个数表示矩阵第i行第j列的元素 输出格式: 输出A^k 共n行,每行n个数,第i行第j个数表示矩阵第i行第j列的元素,每个元素模10^9+7 输入输出样例 输入样例#1: 2 1 1 1 1 1 输出样例#1: 1 1 1 1 说明 n<=100, k<=10^12, |矩阵元素|<=1000 算法:矩阵快速幂

洛谷P3390 【模板】矩阵快速幂

题目背景 矩阵快速幂 题目描述 给定n*n的矩阵A,求A^k 输入输出格式 输入格式: 第一行,n,k 第2至n+1行,每行n个数,第i+1行第j个数表示矩阵第i行第j列的元素 输出格式: 输出A^k 共n行,每行n个数,第i行第j个数表示矩阵第i行第j列的元素,每个元素模10^9+7 输入输出样例 输入样例#1: 2 1 1 1 1 1 输出样例#1: 1 1 1 1 说明 n<=100, k<=10^12, |矩阵元素|<=1000 算法:矩阵快速幂 题解:蒟蒻的模板库 代码: #i

洛谷—— P2117 小Z的矩阵

https://www.luogu.org/problemnew/show/2117 题目描述 小Z最近迷上了矩阵,他定义了一个对于一种特殊矩阵的特征函数G.对于N*N的矩阵A,A的所有元素均为0或1,则G(A)等于所有A[i][j]*A[j][i]的和对2取余之后的结果.举一个例子: 对于上图这个3*3矩阵A,G(A)=(1*1+1*0+1*1+0*1+1*1+1*0+1*1+ 0*1+0*0) mod 2=0 当然询问一个矩阵的G值实在是太简单了.小Z在给出一个N*N矩阵的同时将给你Q个操作

洛谷——P2117 小Z的矩阵

P2117 小Z的矩阵 题目描述 小Z最近迷上了矩阵,他定义了一个对于一种特殊矩阵的特征函数G.对于N*N的矩阵A,A的所有元素均为0或1,则G(A)等于所有A[i][j]*A[j][i]的和对2取余之后的结果.举一个例子: 对于上图这个3*3矩阵A,G(A)=(1*1+1*0+1*1+0*1+1*1+1*0+1*1+ 0*1+0*0) mod 2=0 当然询问一个矩阵的G值实在是太简单了.小Z在给出一个N*N矩阵的同时将给你Q个操作,操作描述如下: 操作1:形如一个整数1和一个整数x,表示将第