Codeforces 题目传送门 & 洛谷题目传送门

一道还算不错的矩乘 tea 罢,不过做过类似的题应该就比较套路了……

首先考虑对于一个固定的序列 \(\{a\}\) 怎样求其本质不同的序列个数,考虑用一个“动态添加元素”的思想,每次往序列最后添加一个元素 \(x\) 并计算加入这个元素后会新增多少个不同的子序列,显然对于所有原来的子序列,在其后面添上 \(x\) 后得到序列依旧是该序列的子序列,但是我们不能仅仅简简单单地用原来的子序列个数 \(\times 2\) 得到新的序列的子序列个数,因为会出现重复计算的情况。不难发现一个子序列被重复计算当且仅当它的末尾一位是 \(x\),并且它在原来的序列中出现过了。还可以发现所有在原来的序列中出现过,并且末尾一位为 \(x\) 的子序列,去掉末尾一位后仍是原序列的子序列,只有一个例外,那就是单独的 \(x\),因此如果我们记 \(f_{i,x}\) 表示序列 \(\{a_1,a_2,\cdots,a_i\}\) 中有多少个序列以 \(x\) 结尾,那么有 \(f_{i,x}=\sum f_{i-1,y}+1\)。(qwq 其实在这道题我自己的解法中就已经用到这个思想了)

接下来考虑原题,看到数据范围 \(10^{18}\),值域却只有 \(30\),一脸矩乘,并且刚刚 \(dp\) 转移方程式又恰好可以写成矩乘的形式,即假设 \(a_i=x\),那么 \(\begin{bmatrix}f_{i,0}\\f_{i,1}\\f_{i,2}\\\cdots\\f_{i,k-1}\\1\end{bmatrix}=\begin{bmatrix}1&0&0&\cdots&0\\0&1&0&\cdots&0\\\vdots&\vdots&\ddots&\cdots&\vdots\\1&1&1&\cdots&1\\\vdots&\vdots&\vdots&\vdots&\vdots\\0&0&0&\cdots&1\end{bmatrix}\times \begin{bmatrix}f_{i-1,0}\\f_{i-1,1}\\f_{i-1,2}\\\cdots\\f_{i-1,k-1}\\1\end{bmatrix}\),其中转移矩阵满足第 \(x\) 行及对角线上所有元素都是 \(0\),其余元素都是 \(1\)。

可是问题又来了,此题序列长度高达 \(10^{18}\),不可能对每个元素都做一遍矩乘,不然复杂度肯定爆炸,有什么优化的办法呢?注意到此题的一个性质,那就是对于所有各位数字和模 \(k\) 相同的整数 \(x,y\) 和非负整数 \(z\),必然有子序列 \(a[x...x+k^z-1]\) 与子序列 \(a[y...y+k^z-1]\) 完全相同,因此我们可以将所有形如 \(a[x...x+k^z]\) 的子序列划分成 \(k\) 个等价类,第 \(i\) 类表示 \(x\) 各位数字和 \(\bmod k=i\) 的那一类,再预处理出 \(A_{x,z}\) 表示 \(a[x...x+k^z]\) 转移矩阵的乘积,那么有 \(A_{x,z}=A_{x,z-1}\times A_{x+1,z-1}\times\cdots\times A_{k-1,z-1}\times A_{0,z-1}\times\cdots\times A_{x-1,z-1}\),暴力计算是 \(k^4\) 的,不过用爪子想想也可以用前后缀积优化到 \(k^3\)。

最后求出 \(n\) 在 \(k\) 进制下的表达式,记作 \((a_ma_{m-1}\cdots a_1a_0)_k\),那么所有转移矩阵连乘的结果就是 \(\prod\limits_{i=m}^0\prod\limits_{j=0}^{a_i}A_{j,i}\)(左边的 \(\prod\limits_{i=m}^0\) 表示倒序枚举,写的可能不是特别规范,不过大概意思懂就行了罢),这个随便算算即可,复杂度 \(\log_knk^3\),可以通过此题。

const int LOG=60;
const int MAXM=30;
const int MOD=1e9+7;
ll n;int m,d[LOG+2],dc=-1;
struct mat{
int a[MAXM+2][MAXM+2];
mat(){memset(a,0,sizeof(a));}
mat operator *(const mat &rhs){
mat ret;
for(int i=0;i<=m;i++) for(int j=0;j<=m;j++) for(int k=0;k<=m;k++)
ret.a[i][j]=(ret.a[i][j]+1ll*a[i][k]*rhs.a[k][j])%MOD;
return ret;
}
} ans,mul,a[LOG+2][MAXM+2],suf[LOG+2][MAXM+2],pre[LOG+2][MAXM+2];
int main(){
scanf("%lld%d",&n,&m);
while(n){d[++dc]=n%m;n/=m;}
for(int i=0;i<=dc;i++){
if(!i){
for(int j=0;j<m;j++){
a[i][j].a[m][m]=1;
for(int k=0;k<m;k++) if(k^j) a[i][j].a[k][k]=1;
for(int k=0;k<=m;k++) a[i][j].a[j][k]=1;
// printf("A %d %d:\n",i,j);
// for(int k=0;k<=m;k++) for(int l=0;l<=m;l++)
// printf("%d%c",a[i][j].a[k][l],(l==m)?'\n':' ');
}
} else {
for(int j=0;j<m;j++){
if(!j) a[i][j]=suf[i-1][0];
else a[i][j]=suf[i-1][j]*pre[i-1][j-1];
// printf("A %d %d:\n",i,j);
// for(int k=0;k<=m;k++) for(int l=0;l<=m;l++)
// printf("%d%c",a[i][j].a[k][l],(l==m)?'\n':' ');
}
}
pre[i][0]=a[i][0];
for(int j=1;j<m;j++) pre[i][j]=pre[i][j-1]*a[i][j];
suf[i][m-1]=a[i][m-1];
for(int j=m-2;~j;j--) suf[i][j]=a[i][j]*suf[i][j+1];
} int sum=0;ans.a[m][0]=1;
for(int i=0;i<=m;i++) mul.a[i][i]=1;
for(int i=dc;~i;i--){
while(d[i]){
d[i]--;mul=mul*a[i][sum];
sum++;if(sum==m) sum=0;
}
} ans=mul*ans;int ret=0;
for(int i=0;i<=m;i++) ret=(ret+ans.a[i][0])%MOD;
printf("%d\n",ret%MOD);
return 0;
}

Codeforces 497E - Subsequences Return(矩阵乘法)的更多相关文章

  1. codeforces 497E Subsequences Return

    codeforces 497E Subsequences Return 想法 做完这题,学了一些东西. 1.求一个串不同子序列个数的两种方法.解一 解二 2.这道题 \(n\) 很大,很容易想到矩阵加 ...

  2. 【CF497E】Subsequences Return 矩阵乘法

    [CF497E]Subsequences Return 题意:设$s_k(x)$表示x在k进制下各位数的和mod k的值.给出k,现有序列$s_k(1),s_k(2),...s_k(n)$.求这个序列 ...

  3. Codeforces 1106F Lunar New Year and a Recursive Sequence | BSGS/exgcd/矩阵乘法

    我诈尸啦! 高三退役选手好不容易抛弃天利和金考卷打场CF,结果打得和shi一样--还因为queue太长而unrated了!一个学期不敲代码实在是忘干净了-- 没分该没分,考题还是要订正的 =v= 欢迎 ...

  4. Codeforces 506E - Mr. Kitayuta's Gift(神仙矩阵乘法)

    Codeforces 题目传送门 & 洛谷题目传送门 神仙题 %%%%%%%%%%%%% u1s1 感觉这道题风格很省选( 下记 \(m=|s|\),首先探讨 \(n+m\) 为偶数的情形. ...

  5. Codeforces 1368H - Breadboard Capacity(最小割+线段树维护矩阵乘法)

    Easy version:Codeforces 题面传送门 & 洛谷题面传送门 Hard version:Codeforces 题面传送门 & 洛谷题面传送门 首先看到这种从某一种颜色 ...

  6. Codeforces 750E - New Year and Old Subsequence(线段树维护矩阵乘法,板子题)

    Codeforces 题目传送门 & 洛谷题目传送门 u1s1 我做这道 *2600 的动力是 wjz 出了道这个套路的题,而我连起码的思路都没有,wtcl/kk 首先考虑怎样对某个固定的串计 ...

  7. Codeforces 506E Mr. Kitayuta's Gift (矩阵乘法,动态规划)

    描述: 给出一个单词,在单词中插入若干字符使其为回文串,求回文串的个数(|s|<=200,n<=10^9) 这道题超神奇,不可多得的一道好题 首先可以搞出一个dp[l][r][i]表示回文 ...

  8. codeforces 691E(矩阵乘法)

    E. Xor-sequences time limit per test 3 seconds memory limit per test 256 megabytes input standard in ...

  9. Codeforces 576D - Flights for Regular Customers(bitset 优化广义矩阵乘法)

    题面传送门 题意: 有一张 \(n\) 个点 \(m\) 条边的有向图,你初始在 \(1\) 号点,边上有边权 \(c_i\) 表示只有当你经过至少 \(c_i\) 条边的时候你才能经过第 \(i\) ...

随机推荐

  1. 【UE4 C++ 基础知识】<12> 多线程——FRunnable

    概述 UE4里,提供的多线程的方法: 继承 FRunnable 接口创建单个线程 创建 AsyncTask 调用线程池里面空闲的线程 通过 TaskGraph 系统来异步完成一些自定义任务 支持原生的 ...

  2. MacOS安装使用Kettle

    一.环境说明 操作系统版本:macOS Big Sur 11.6.1 机型:Intel版本 JDK版本:Amazon Corretto-openjdk8 Kettle版本:Kettle8.9 二.问题 ...

  3. [敏捷软工团队博客]The Agiles 团队介绍&团队采访

    项目 内容 课程:北航-2020-春-敏捷软工 博客园班级博客 作业要求 团队作业-团队介绍和采访 团队名称来源 The Agile is The Agile. 敏捷就是敏捷.我们只是敏捷的践行者罢了 ...

  4. seata整合多数据源

    seata整合多数据源 一.背景 二.整合步骤 1.seata server的搭建 2.引入数据源切换组件 3.引入seata组件 4.配置多数据源 5.关闭seata自己默认的数据源代理 6.配置s ...

  5. netty中使用protobuf实现多协议的消息

    在我们使用 netty 的过程中,有时候为了高效的传输数据,经常使用 protobuf 进行数据的传输,netty默认情况下为我们实现的 protobuf 的编解码,但是默认的只能实现单个对象的编解码 ...

  6. 2021.9.28考试总结[NOIP模拟64]

    T1 三元组 发现确定\(b,c\)的情况下,\(a\)的值域是连续的.确定\(b\)后\(a+b\)的取值是\([1+b,b+b]\).树状数组维护对每个\(b\)可行的\(c\). 注意取模后取值 ...

  7. Linux C语言链表详细分析

    链表是一种常见的基础数据结构,结构体指针在这里得到了充分的利用.链表可以动态的进行存储分配,也就是说,链表是一个功能极为强大的数组,他可以在节点中定义多种数据类型,还可以根据需要随意增添,删除,插入节 ...

  8. Swarm+Docker+Portainer(集群,图形化)

    参考文章 https://blog.csdn.net/u011781521/article/details/80469804 https://blog.csdn.net/u011781521/arti ...

  9. Loto实践干货(8)loto示波器在LED台灯调光问题维修中的应用案例

    Loto实践干货(8)loto示波器在LED台灯调光问题维修中的应用案例 一位客户最近觉得觉得他的LED台灯好闪, 于是拆了看看,里面的控制板是这样的: 干掉双色调光功能,只调亮度的话闪烁的状况能好转 ...

  10. 你们不要再吵了! Java只有值传递..

    写在前边 上次聊到Java8新特性 lambda时,有小伙伴在评论区提及到了lambda对于局部变量的引用,补充着博客的时候,知识点一发散就有了这篇对于值传递还是引用传递的思考.关于这个问题为何会有如 ...