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. Kali安装OWASP

    我是2019版的kali,里面并没有自带OWASP工具,因为OWASP不再更新的因素,所以新版kali将它移除了  安装OWASP apt-get install zaproxy #以下都是安装软件时 ...

  2. docker逃逸漏洞复现(CVE-2019-5736)

    漏洞概述 2019年2月11日,runC的维护团队报告了一个新发现的漏洞,SUSE Linux GmbH高级软件工程师Aleksa Sarai公布了影响Docker, containerd, Podm ...

  3. 解决git clone慢问题

    解决git clone慢 关于Git克隆或是上传代码龟速的问题真是让人很恼火,这里对于网上的两种解决方案进行摘录. 利用码云克隆github项目 亲测有效 进入码云,新建一个仓库: 在创建的最后选择导 ...

  4. find&正则表达式

    标准的正则表示式格式 常用元字符 代码 说明 . 匹配除换行符以外的任意字符 \w 匹配字母或数字或下划线 \s 匹配任意的空白符 \d 匹配数字 \b 匹配单词的开始或结束 ^ 匹配字符串的开始 $ ...

  5. arm开发板上找不到/dev/i2c-*设备

    最近在调试arm与外设iic通讯是,想来个投机取巧,先不写单独的驱动,直接通过iic bus设备是否可以连接到外设,然后发现在板子上找不到"/dev/i2c-n"的设备,标准的系统 ...

  6. Python super(Todo,self).__init__() TypeError: super() argument 1 must be type, not classobj

    示例如下 class A(): def __init__(self):pass class B(A): def __init__(self): super(A, self).__init__() 当调 ...

  7. Ubuntu virtualenv 创建 python3 虚拟环境 激活 退出

    首先默认安装了virtualenv 创建python3虚拟环境 your-name@node-name:~/virtual_env$ virtualenv -p /usr/bin/python3 py ...

  8. 百亿级小文件存储,JuiceFS 在自动驾驶行业的最佳实践

    自动驾驶是最近几年的热门领域,专注于自动驾驶技术的创业公司.新造车企业.传统车厂都在这个领域投入了大量的资源,推动着 L4.L5 级别自动驾驶体验能尽早进入我们的日常生活. 自动驾驶技术实现的核心环节 ...

  9. vue路由监听和参数监听

    1.路由携带数据跳转 routerAction(hideDisplays, data) { switch (hideDisplays) { case "pubAccountMenu" ...

  10. lamp 架构的理解

    1,lamp架构下的求情过程如下: 2,httpd服务器连接php服务器的三种方式 3,php和mysql的连接