Codeforces 497E - Subsequences Return(矩阵乘法)
一道还算不错的矩乘 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(矩阵乘法)的更多相关文章
- codeforces 497E Subsequences Return
codeforces 497E Subsequences Return 想法 做完这题,学了一些东西. 1.求一个串不同子序列个数的两种方法.解一 解二 2.这道题 \(n\) 很大,很容易想到矩阵加 ...
- 【CF497E】Subsequences Return 矩阵乘法
[CF497E]Subsequences Return 题意:设$s_k(x)$表示x在k进制下各位数的和mod k的值.给出k,现有序列$s_k(1),s_k(2),...s_k(n)$.求这个序列 ...
- Codeforces 1106F Lunar New Year and a Recursive Sequence | BSGS/exgcd/矩阵乘法
我诈尸啦! 高三退役选手好不容易抛弃天利和金考卷打场CF,结果打得和shi一样--还因为queue太长而unrated了!一个学期不敲代码实在是忘干净了-- 没分该没分,考题还是要订正的 =v= 欢迎 ...
- Codeforces 506E - Mr. Kitayuta's Gift(神仙矩阵乘法)
Codeforces 题目传送门 & 洛谷题目传送门 神仙题 %%%%%%%%%%%%% u1s1 感觉这道题风格很省选( 下记 \(m=|s|\),首先探讨 \(n+m\) 为偶数的情形. ...
- Codeforces 1368H - Breadboard Capacity(最小割+线段树维护矩阵乘法)
Easy version:Codeforces 题面传送门 & 洛谷题面传送门 Hard version:Codeforces 题面传送门 & 洛谷题面传送门 首先看到这种从某一种颜色 ...
- Codeforces 750E - New Year and Old Subsequence(线段树维护矩阵乘法,板子题)
Codeforces 题目传送门 & 洛谷题目传送门 u1s1 我做这道 *2600 的动力是 wjz 出了道这个套路的题,而我连起码的思路都没有,wtcl/kk 首先考虑怎样对某个固定的串计 ...
- Codeforces 506E Mr. Kitayuta's Gift (矩阵乘法,动态规划)
描述: 给出一个单词,在单词中插入若干字符使其为回文串,求回文串的个数(|s|<=200,n<=10^9) 这道题超神奇,不可多得的一道好题 首先可以搞出一个dp[l][r][i]表示回文 ...
- codeforces 691E(矩阵乘法)
E. Xor-sequences time limit per test 3 seconds memory limit per test 256 megabytes input standard in ...
- Codeforces 576D - Flights for Regular Customers(bitset 优化广义矩阵乘法)
题面传送门 题意: 有一张 \(n\) 个点 \(m\) 条边的有向图,你初始在 \(1\) 号点,边上有边权 \(c_i\) 表示只有当你经过至少 \(c_i\) 条边的时候你才能经过第 \(i\) ...
随机推荐
- 【UE4 C++ 基础知识】<12> 多线程——FRunnable
概述 UE4里,提供的多线程的方法: 继承 FRunnable 接口创建单个线程 创建 AsyncTask 调用线程池里面空闲的线程 通过 TaskGraph 系统来异步完成一些自定义任务 支持原生的 ...
- MacOS安装使用Kettle
一.环境说明 操作系统版本:macOS Big Sur 11.6.1 机型:Intel版本 JDK版本:Amazon Corretto-openjdk8 Kettle版本:Kettle8.9 二.问题 ...
- [敏捷软工团队博客]The Agiles 团队介绍&团队采访
项目 内容 课程:北航-2020-春-敏捷软工 博客园班级博客 作业要求 团队作业-团队介绍和采访 团队名称来源 The Agile is The Agile. 敏捷就是敏捷.我们只是敏捷的践行者罢了 ...
- seata整合多数据源
seata整合多数据源 一.背景 二.整合步骤 1.seata server的搭建 2.引入数据源切换组件 3.引入seata组件 4.配置多数据源 5.关闭seata自己默认的数据源代理 6.配置s ...
- netty中使用protobuf实现多协议的消息
在我们使用 netty 的过程中,有时候为了高效的传输数据,经常使用 protobuf 进行数据的传输,netty默认情况下为我们实现的 protobuf 的编解码,但是默认的只能实现单个对象的编解码 ...
- 2021.9.28考试总结[NOIP模拟64]
T1 三元组 发现确定\(b,c\)的情况下,\(a\)的值域是连续的.确定\(b\)后\(a+b\)的取值是\([1+b,b+b]\).树状数组维护对每个\(b\)可行的\(c\). 注意取模后取值 ...
- Linux C语言链表详细分析
链表是一种常见的基础数据结构,结构体指针在这里得到了充分的利用.链表可以动态的进行存储分配,也就是说,链表是一个功能极为强大的数组,他可以在节点中定义多种数据类型,还可以根据需要随意增添,删除,插入节 ...
- Swarm+Docker+Portainer(集群,图形化)
参考文章 https://blog.csdn.net/u011781521/article/details/80469804 https://blog.csdn.net/u011781521/arti ...
- Loto实践干货(8)loto示波器在LED台灯调光问题维修中的应用案例
Loto实践干货(8)loto示波器在LED台灯调光问题维修中的应用案例 一位客户最近觉得觉得他的LED台灯好闪, 于是拆了看看,里面的控制板是这样的: 干掉双色调光功能,只调亮度的话闪烁的状况能好转 ...
- 你们不要再吵了! Java只有值传递..
写在前边 上次聊到Java8新特性 lambda时,有小伙伴在评论区提及到了lambda对于局部变量的引用,补充着博客的时候,知识点一发散就有了这篇对于值传递还是引用传递的思考.关于这个问题为何会有如 ...