博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ACdream 1093 女神的正多面体 矩阵快速幂
阅读量:5955 次
发布时间:2019-06-19

本文共 2653 字,大约阅读时间需要 8 分钟。

题目大意:给你三种正多边形,给你起点s,终点e以及最多行走的步数k,问有多少种路径方案(路径中只要有一个顶点不同即视为不同)。

题目分析:

可以通过矩阵快速幂求解。

为每个正多边形(最多三个)构建一个邻接矩阵A,然后第K步的方案数即为A^k。

结果即为A^1 + A^2 + A^3 + ...... + A^k.

对于这种形式的矩阵运算,我们可以把它拆分成:

k为奇:ans = (A^1 + A^2 + ... + A^(k/2)) + (A^1 + A^2 + ... + A^(k/2)) * A^(k.2) + A^k;

k为偶:ans = (A^1 + A^2 + ... + A^(k/2)) + (A^1 + A^2 + ... + A^(k/2)) * A^(k.2);

合并一下就是:

ans = (A^1 + A^2 + ... + A^(k/2)) * (A(k/2) + 1);

if(k & 1) ans = ans + A^k;

结果即为mat[s - 1][e - 1](保存的时候下标均以减一)。

PS:本蒟蒻的代码效率貌似一直不高的样子QUQ。。。路过的众神们见谅QUQ。。。

代码如下:

#include 
#include
#define REP(i, n) for(int i = 0; i < n; ++i)typedef long long ll;const int mod = 1000000007;const int O = 8;int N, K;typedef struct M{ ll mat[O][O]; M operator * (const M &t) const{
//重载矩阵乘法 M tmp; memset(tmp.mat, 0, sizeof(tmp.mat)); REP(i, N) REP(j, N) REP(k, N) tmp.mat[i][j] = (tmp.mat[i][j] + mat[i][k] * t.mat[k][j]) % mod; return tmp; } //不使用函数的原因是为了让快速幂看起来更加自然 M operator + (const M &t) const{
//重载矩阵加法 M tmp; REP(i, N) REP(j, N) tmp.mat[i][j] = (mat[i][j] + t.mat[i][j]) % mod; return tmp; }}M;M A[3] = { {
{
//正四边形 {
0, 1, 1, 1}, {
1, 0, 1, 1}, {
1, 1, 0, 1}, {
1, 1, 1, 0}, }}, {
{
//正六边形 {
0, 1, 0, 1, 1, 0, 0, 0}, {
1, 0, 1, 0, 0, 1, 0, 0}, {
0, 1, 0, 1, 0 ,0, 1, 0}, {
1, 0, 1, 0, 0, 0, 0, 1}, {
1, 0, 0, 0, 0, 1, 0, 1}, {
0, 1, 0, 0, 1, 0, 1, 0}, {
0, 0, 1, 0, 0 ,1, 0, 1}, {
0, 0, 0, 1, 1, 0, 1, 0}, }}, {
{
//正八边形 {
0, 1, 1, 1, 1, 0}, {
1, 0, 1, 0, 1, 1}, {
1, 1, 0, 1, 0, 1}, {
1, 0, 1, 0, 1, 1}, {
1, 1, 0, 1, 0, 1}, {
0, 1, 1, 1, 1, 0}, }},}, E;M pow(ll k){
//矩阵快速幂求A^k. M res = E, tmp = A[K]; for(; k; k >>= 1){ if(k & 1) res = res * tmp; tmp = tmp * tmp; } return res;}M _pow(ll k){
//递归快速幂求A^1 + A^2 + A^3 + ...... + A^k. if(k == 1) return A[K]; M res = _pow(k >> 1) * (E + pow(k >> 1)); if(k & 1) res = res + pow(k); return res;}void work(){ int t, n, s, e; ll k; REP(i, O) REP(j, O) E.mat[i][j] = (i == j);//初始化单位矩阵 scanf("%d", &t); while(t--){ scanf("%d%lld%d%d", &n, &k, &s, &e); N = (n == 4 ? 4 : (n == 6 ? 8 : 6));//选择矩阵需要的范围 K = (n == 4 ? 0 : (n == 6 ? 1 : 2));//选择正多边形的类型 printf("%lld\n", _pow(k).mat[s - 1][e - 1]); }}int main(){ work(); return 0;}
1093

在此附上ACdream区域赛指导赛之专题赛系列(1)の数学专场解题报告,本题即E题。http://acdream.info/topic/1451

转载于:https://www.cnblogs.com/ac-luna/p/3750800.html

你可能感兴趣的文章
我的友情链接
查看>>
golang xml和json的解析与生成
查看>>
javascript 操作DOM元素样式
查看>>
Android 内存管理 &Memory Leak & OOM 分析
查看>>
【查找算法】基于存储的查找算法(哈希查找)
查看>>
JavaWeb网上图书商城完整项目--day02-10.提交注册表单功能之页面实现
查看>>
记录一下这次web实训的两个网站
查看>>
POJ-1830 开关问题 高斯消元
查看>>
HDU-4366 Successor 线段树+预处理
查看>>
做程序开发的你如果经常用Redis,这些问题肯定会遇到
查看>>
CAS-认证流程
查看>>
006android初级篇之jni数据类型映射
查看>>
Java 集合框架查阅技巧
查看>>
apache配置虚拟主机
查看>>
CollectionView水平和竖直瀑布流的实现
查看>>
前端知识复习一(css)
查看>>
spark集群启动步骤及web ui查看
查看>>
Maven学习笔记二:常用命令
查看>>
利用WCF改进文件流传输的三种方式
查看>>
Spring学习总结(2)——Spring的常用注解
查看>>