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. linux中文件查找、whereis、which、输出命令

    1.文件查找(find):find是最常⻅和最强⼤的查找命令 格式:find / -name  文件名,比如:find / -name mysql.  (1).模糊查找:*是代表所有的,?是代表⼀个字 ...

  2. 微服务(三) Eureka注册中心和Ribbon负载均衡

    1. Eureka注册中心 1.1 Eureka的结构和作用 在上一篇文章中 微服务(二)服务拆分及远程调用 order-service在发起远程调用的时候,该如何得知user-service实例的i ...

  3. 状压dp学习笔记(紫例题集)

    P3451旅游景点 Tourist Attractions 这个代码其实不算是正规题解的(因为我蒟蒻)是在我们的hzoj上内存限制324MIB情况下过掉的,而且经过研究感觉不太能用滚动数组,所以那这个 ...

  4. Java并发:Condition接口

    Condition 接口与 Lock 配合实现了等待 / 通知模式,这个和 Object 的监视器方法(wait.notify.notifyAll 等方法)一样,都是实现了等待 / 通知模式,但这两者 ...

  5. linux c语言 rename的用法-rename() does not work across different mount points, even if the same file system is mounted on both

    最近在一个项目上执行文件的搬移功能时发现总是失败,临时录像文件存放于emmc的/tmp/目录下,当录像完成时候则调用rename企图将此文件搬到/mnt/sdcard/mmcblk1p1/(这是外置的 ...

  6. Python AttributeError: module 'string' has no attribute 'atoi'

    python2 中可以用string.atoi 在python3中会报错 替换的方案是 string.atoi(your_str) 替换为 int(your_str) 这个代码python2和pyth ...

  7. hdu 1198 Farm Irrigation(并查集)

    题意: Benny has a spacious farm land to irrigate. The farm land is a rectangle, and is divided into a ...

  8. 第39篇-Java通过JNI调用C/C++函数

    在某些情况下,Java语言需要通过调用C/C++函数来实现某些功能,因为Java有时候对这些功能显的无能为力,如想使用X86_64 的 SIMD 指令提升一下业务方法中关键代码的性能,又或者想要获取某 ...

  9. 在代码生成工具Database2Sharp中增加Vue&Element 工作流页面的快速生成

    在我们基于框架开发系统的时候,往往对一些应用场景的页面对进行了归纳总结,因此对大多数情况下的页面呈现逻辑都做了清晰的分析,因此在我们基于框架的基础上,增量式开发业务功能的时候,能够事半功倍.代码生成工 ...

  10. go条件语句

    1. if else package main import "fmt" func main(){ a :=123 if a>100{ fmt.prinln("大于 ...