• SHOI2013 超级跳马


    我是常年游荡于题解区的幽灵。

    直观的想法就是前缀和+差分优化DP, 但还有些比较奇妙的方法or trick:

    1. (f[i][j] = f[i-1][j-1]+f[i-1][j]+f[i-1][j+1]+color{red}{f[i-2][j]}), 因为可以一步跳到 (f[i][j]) 的状态也可以一步跳到 (f[i-2][j]), 反过来也成立 。

    2. 只考虑从左边某个特定的列的转移矩阵, 设为 (J), 设第 (i) 列的答案矩阵是 (A_i), 则有:(A_n = J*(A_{n-1}+A_{n-3}+A_{n-5}+cdots))(A_{n-2} = J*(A_{n-3}+A_{n-5}+A_{n-7}+cdots)), 不难得出 (A_n = J*A_{n-1}+A_{n-2}), 这也是个递推, 构造矩阵:

    [[ egin{matrix} J & E\ E & O end{matrix} ] * [ egin{matrix} A_n\ A_{n+1} end{matrix} ]=[ egin{matrix} A_{n+1}\ A_{n} end{matrix} ] ]

    其中 (E) 是单位矩阵而 (O) 是全零矩阵,就可以大力递推了。

    1. 这个, 建图

    接下来选择性地实现/口胡上述的某些解法(我挺中意矩阵套矩阵的解法)


    直观解法

    s0[i] 维护与当前列差偶数列的第 i 行的方案数之和, s1[i] 则是相差奇数列的。

    考虑转移到下一列, 则有:
    s0[i] <- s1[i] + s0[i-1] + s0[i] + s0[i+1]

    s1[i] <- s0[i]


    矩阵套矩阵

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int mo = 30011;
    int n,m;
    
    int qm(int x) { return x>=mo?x-mo:x; }
    
    struct M{
    	int t[51][51];
    	M() {memset(t,0,sizeof t);  }
    };
    M operator*(const M &a, const M &b) {
    	M c; for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)for(int k=1;k<=n;++k)
    			c.t[i][j] = qm(c.t[i][j] + a.t[i][k]*b.t[k][j]%mo);
    	return c;
    }
    M operator+(const M &a, const M &b) {
    	M c; for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)
    			c.t[i][j] = qm(a.t[i][j] + b.t[i][j]);
    	return c;
    }
    
    struct M2{ M t[3][3]; } S,T,Delta;
    M2 operator*(const M2 &a, const M2 &b) {
    	M2 c; for(int i=1;i<=2;++i)for(int j=1;j<=2;++j)for(int k=1;k<=2;++k)
    			c.t[i][j]= c.t[i][j] + a.t[i][k]*b.t[k][j];
    	return c;
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	S.t[1][1].t[1][1] = S.t[1][1].t[2][1] = 1;//µÚ¶þÁеĴ𰸾ØÕó
    	if(m==2) return printf("%d",S.t[1][1].t[n][1]),0;
    	for(int i=1;i<=n;++i) {
    		T.t[1][2].t[i][i] = T.t[2][1].t[i][i] = 1;
    		T.t[1][1].t[i][i-1] = T.t[1][1].t[i][i] =T.t[1][1].t[i][i+1] = 1;
    	}
    	m -= 3;
    	Delta = T;
    	while(m)
    	{
    		if(m&1) Delta = Delta * T;
    		T = T*T;
    		m >>= 1;
    	}
    	S = Delta*S;
    	printf("%d",S.t[1][1].t[n][1]);
    	return 0;
    }
    
  • 相关阅读:
    Linux根目录各个文件夹介绍及说明
    CentOS7 yum方式安装MySQL5.7
    spring-boot 启动图标修改-启动彩蛋
    Android 4.4从图库选择图片,获取图片路径并裁剪
    Android开发之获取相册照片和获取拍照照片二
    Android开发之获取相册照片和获取拍照照片
    httpclient 发送文件和字符串信息
    HttpURLConnection 发送 文件和字符串信息
    Android中使用HTTP服务
    android http json请求3种不同写法
  • 原文地址:https://www.cnblogs.com/tztqwq/p/14034760.html
Copyright © 2020-2023  润新知