CCF CSP 202006-4 1246 (100分详细题解,矩阵乘法+快速幂)

news2024/11/24 13:47:20

202006-4 1246 (100分详细题解,矩阵乘法+快速幂)

在这里插入图片描述

可以先看下csp官方的思路讲解,大思路是状态转移,先看下面s<=2的情况

1 -> 2
2 -> 4
4 -> 16
6 -> 6 64 4
16 -> 26(不考虑26464的原因是,16可以拆分为16,而1->2 , 6-> 64, 6, 4,去除冗余解)
... 详细见尾部代码

s<=2共有14个数字,故可以将这个14个数字离散化到0~13,形成14*14转移矩阵,随后根据线性代数矩阵的结合律,这14个数字构成一个行向量a,可以使用矩阵快速幂,快速得到这14个数字出现的次数。由于向量a初始时为{1,0…0},故代码中直接由res矩阵的第0行充当。

当s>2时,可以进行倒推,如:464 上一次由 26操作而来。同时考虑到题目给的s是一个部分数字串,故可能无法直接倒推回s=2,故s在整个序列的情况,可能分为s前面是1,s前面是6,或者s前面不是1或6, 因为4->16 6->64,都会产生两位,所以s的首个数字可能是16中的6,以及64中的6,由于s只是其中的一部分,所以我们要在前面补上1和6。你可能回想为什么不在后面补1和6,其实也考虑了,不过在代码中用i + 1 == str.size()来解决了。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
const int N = 14, MOD = 998244353;

int n;
string S;
int id[100];        // id[x]将x映射到0~13
vector<int> vers{
    1, 2, 4, 6, 16, 26, 41, 42, 44,
    46, 61, 62, 64, 66
};
// 上面的数字进行运算后可以得出下面的贡献,两位数字的运算后的数字只有一个
// 如16->26(不考虑2,6,4,64的原因是,16可以拆分为1和6,而1->2 , 6->64, 6, 4)
// 故两位数字运算后只转移到前一位数字幂的后一位和后一位数字幂的前一位

// 当s的长度大于2时,我们可以根据转移的规律,逆推到s只有两位的情况。
// s在整个序列的情况,可能分为s前面是1,s前面是6,或者s前面不是1或6.
// 因为4->16 6->64,都会产生两位,所以s的首个数字可能是16中的6,以及64中的6,由于s只是其中的一部分,所以我们要补上1和6
vector<vector<int>> g{
    {2}, {4}, {1, 6, 16}, {6, 4, 64}, {26},
    {46}, {62}, {64}, {61}, {66}, {42},
    {44}, {41}, {46}
};
int tr[N][N];       // tr的第j列是对ver[j]的贡献

void init() {
    memset(id, -1, sizeof id);
    for (int i = 0; i < N; i++) id[vers[i]] = i;        // 映射
    //求转移矩阵
    for (int i = 0; i < N; i++)
        for (auto x : g[i])
            tr[i][id[x]] ++;
}

void mul(int c[][N], int a[][N], int b[][N]) {
    static int tmp[N][N];
    memset(tmp, 0, sizeof tmp);
    for (int i = 0; i < N; i++)     // 行
        for (int j = 0; j < N; j++)     // 列
            for (int k = 0; k < N; k++)     // 行×列
                tmp[i][j] = (tmp[i][j] + (LL)a[i][k] * b[k][j]) % MOD;
    memcpy(c, tmp, sizeof tmp);
}

int qmi(int k, int id) {
    if (id == -1) return 0;
    int res[N][N] = { 0 }, w[N][N];
    memcpy(w, tr, sizeof w);
    res[0][0] = 1;      // 初始,使用res的首行充当0时刻的行向量

    while (k) {
        if (k & 1) mul(res, res, w); //res=res*w
        mul(w, w, w);   // w=w*w;
        k >>= 1;
    }
    return res[0][id];
}

string get(string str) {
    string res;
    for (int i = 0; i < str.size(); i++)
        if (str[i] == '2') res += '1';
        else if (str[i] == '4') res += '2';
        else if (str[i] == '1') {
            if (i + 1 == str.size() || str[i + 1] == '6') res += '4', i++;
            else return "";
        } else {
            if (i + 1 == str.size() || str[i + 1] == '4') res += '6', i++;
            else return "";
        }
    return res;
}

int dfs(int k, string& str) {
    if (str.size() <= 2) return qmi(k, id[stoi(str)]);
    int res = 0;
    for (string s : {"", "1", "6"}) {
        auto t = get(s + str);
        if (t.size()) res = (res + dfs(k - 1, t)) % MOD;        // !!!!!!!
    }
    return res;
}

int main() {
    init();
    cin >> n >> S;
    cout << dfs(n, S) << endl;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1494746.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务自动化管理初步认识与使用

目录 一、ETCD 1.1、ETCD简介 对于实施工程师&#xff1a; 1.2、特点 1.3. 使用场景 1.4、 关键字 1.5 工作原理 二、ETCD的安装 2.1、下载路径 2.2、介绍 2.3、具体操作 安装服务端 安装etcd客户端 测试 三、ETCD使用 3.1、前奏具体操作 3.2、 常用操作 一、ET…

Java开发进大厂面试必备技能,面试初级java工程师问题

前言 今天的分享主要是讲下这个 redis&#xff0c;什么是缓存雪崩、穿透和击穿。这三个技术问题是我们平时开发工作中和面试过程中&#xff0c;必须要会的知识点&#xff0c;因为目前的互联网系统没有几个不需要用到缓存的&#xff0c;只要用到缓存的话&#xff0c;就需要掌握…

【OJ】日期差值与日期累加

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1. KY111 日期差值1.1 题目分析1.2 代码 2. KY258 日期累加2.1 题目分析2.2 代码 1. KY111 日期差值 1.1 题目分析 日期之间比较可能会出现给的两个年月日都不相同&#xff0c;这个就不好作差&#xff0c;每个月给的…

Apache POI 解析和处理Excel

摘要&#xff1a;由于开发需要批量导入Excel中的数据&#xff0c;使用了Apache POI库&#xff0c;记录下使用过程 1. 背景 Java 中操作 Excel 文件的库常用的有Apache POI 和阿里巴巴的 EasyExcel 。Apache POI 是一个功能比较全面的 Java 库&#xff0c;适合处理复杂的 Offi…

Stable Diffusion V3测评

1.引言 3月5号&#xff0c;Stability AI发布了介绍Stable Diffusion V3的研究论文&#xff0c;链接地址&#xff1a;戳我 这是目前他们发布的最先进、功能最强大的图像生成器&#xff0c;与一年多前发布的令人印象深刻的 Stable Diffusion V2.1 相比有了大幅升级。SD3所带来的…

redis进阶(一)

文章目录 前言一、Redis中的对象的结构体如下&#xff1a;二、压缩链表三、跳跃表 前言 Redis是一种key/value型数据库&#xff0c;其中&#xff0c;每个key和value都是使用对象表示的。 一、Redis中的对象的结构体如下&#xff1a; /** Redis 对象*/ typedef struct redisO…

软考65-上午题-【面向对象技术】-面向对象分析、设计、测试

一、面向对象分析OOA 1-1、面向对象分析的定义 面向对象分析的目的&#xff1a;为了获得对应用问题的理解。理解的目的是确定系统的功能、性能要求。 面向对象分析包含5个活动&#xff1a;&#xff08;背&#xff01;&#xff09; 认定对象&#xff1b;&#xff08;重要一点…

爆肝!Claude3与ChatGPT-4到底谁厉害,看完你就知道了!

前言&#xff1a; 相信大家在pyq都被这张图片刷屏了把~ 昨天&#xff0c;为大家介绍了一下什么是Claude&#xff0c;今天咱终于弄到号了&#xff08;再被ban了3个号之后终于是成功的登上去了&#xff0c;如果各位看官觉得咱文章写的不错&#xff0c;麻烦点个小小的关注~你们的…

android开发基础有哪些,985研究生入职电网6个月

不好意思久等了 这篇文章让小伙伴们久等了。 一年多以来&#xff0c;关于嵌入式开发学习路线、规划、看什么书等问题&#xff0c;被问得没有一百&#xff0c;也有大几十次了。但是无奈自己对这方面了解有限&#xff0c;所以每次都没法交代&#xff0c;搞得实在不好意思。 但…

Linux conntrack和iptables技术解析

Linux虚拟文件系统管理技术 1. netfilter解析1.1 netfilter的基础原理1.2 netfilter的相关hook 2. conntrack解析2.1 conntrack的基础原理2.2 conntrack的表记录解析 3. iptables解析3.1 iptables基础原理3.2 融合conntrack表的iptables规则 4. 疑问和思考4.1 conntrack和iptab…

【vue3之组合式API】

组合式API 一、setup1.写法2.如何访问3.语法糖4.同步返回对象 二、reactive()和ref()1.reactive()2.ref() 三、computed四、watch函数1侦听单个数据2.侦听多个数据3. immediate4. deep5.精确侦听对象的某个属性 五、生命周期函数六、组件通信1.父传子2. 子传父 七、模版引用1. …

【C++精简版回顾】20.模板的使用

1.模板起源 1.模板的定义 1.针对函数属性模板 //针对函数属性 template <class VOID > VOID print1(int a) {cout << a << endl; } 2.针对数据属性模板 //针对数据属性 template <typename INT,typename FLOAT> void print2(INT a,FLOAT b) {cout <…

网工内推 | 华为成都研究所,24届应届生人才储备计划

华为成都研究所 招聘岗位 网络工程师&#xff08;2024应届&#xff09; 岗位要求 24届的学员 本科公办院校 英语4/6级 有HCIP优先 工作地点 成都 私信小编&#xff0c;回复【内推】&#xff0c;获取内推名额申请资格~ 想获取更多『 思科 | 华为 | 红帽 认证真题 』、『 网…

正向代理和反向代理区别

正向代理和反向代理的区别&#xff1a; 特点正向代理反向代理位置位于客户端和目标服务器之间位于目标服务器和客户端之间代理对象代理服务器代表客户端发送请求到目标服务器代理服务器代表目标服务器接收客户端的请求配置客户端需要手动配置代理服务器客户端不需要知道代理服…

Redis(5.0)

1、什么是Redis Redis是一种开源的、基于内存、支持持久化的高性能Key-Value的NoSQL数据库&#xff0c;它同时也提供了多种数据结构来满足不同场景下的数据存储需求。 2、安装Redis&#xff08;Linux&#xff09; 2.1、去官网&#xff08;http://www.redis.cn/&#xff09;下…

7、Redis-事务、持久化、内存淘汰机制和过期key处理

目录 一、事务 二、持久化 三、内存淘汰机制 四、过期key处理 一、事务 Redis的事务本质上就是一个批量执行命令的操作。分为三个步骤&#xff1a; 开始事务&#xff1a;multi命令入队&#xff1a;正常输入命令即可执行事务&#xff08;依次执行命令&#xff09;&#xf…

最近开发中遇到的一些问题

puppeteer下载失败问题 使用的淘宝镜像&#xff0c;但执行命令npm i puppeteer之后&#xff0c;报错&#xff1a; npm ERR! code 1 npm ERR! path E:\项目-临时\test_install_puppeteer\node_modules\puppeteer npm ERR! command failed npm ERR! command C:\WINDOWS\system3…

Android开发教程入门,那些被大厂优化的程序员们

Binder原理 1、概述 Android系统中&#xff0c;涉及到多进程间的通信底层都是依赖于Binder IPC机制。例如当进程A中的Activity要向进程B中的Service通信&#xff0c;这便需要依赖于Binder IPC。不仅于此&#xff0c;整个Android系统架构中&#xff0c;大量采用了Binder机制作…

数据库原理(关系代数)

1.集合运算符基础 要求&#xff1a; 具有相同的目n&#xff08;即两个关系都有n 个属性&#xff09;相应的属性取自同一个域t是元组变量&#xff0c; t R表示t是R的一个元组 1.1并 符号&#xff08;&#xff09; R∪S { t|t R∨t S } 结果特征&#xff1a; 仍为n 目关…

长度为n的数组a初始值全为0,目标是把数组a变为数组b(1<=bi<=n), 可以进行任意次操作:选择长度为k的数组c,(1<=ci<=n且两两不同)

对于1<i<k, 把 a[c[i]] 改为c[i % k 1]。给定n&#xff0c;k和数组b&#xff0c;判断能否得到数组b。 题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #d…