形态形成场(矩阵乘法优化dp)

形态形成场(矩阵乘法优化dp)

短信中将会涉及前\(k\)种大写字母,每个大写字母都有一个对应的替换式\(Si\),替换式中只会出现大写字母和数字,比如\(A→BB,B→CC0,C→123\),代表 \(A=12312301231230,B=1231230,C=123\)。现在对于给定的替换式,求字符 AA 所代表的串有多少子串满足:

  • 这个子串为单个字符\(0\)或没有前导\(0\)。
  • 把这个子串看作一个十进制数后模\(n\)等于\(0\)。

答案对\(r\)取模。对于100%的数据,$2 \leq r \leq 10^9; 1 \leq k \leq 26; 4 \leq \left| S_i \right| \leq 100 $。

首先可以想出一个暴力dp:\(f[i][j]\)表示到第i位时,模n为j的串的个数,那么显然\(f[i][(10j+s[i])\%n]+=f[i-1][j]\)。复杂度是\(O(len\times n)\)。

但是这样只能拿60分,并不能过这道题。怎么办呢?观察一下题目,其实就是将一个字符的字符串展开以后dp,并且最多展开26层,同一个字符可能被展开多次。有没有想到矩阵优化dp?由于每次\(f[s[i]\%n]\)要加上1,因此不能用传统的矩阵递推数列,还必须在向量中加上一维常量1。为了方便,再在向量中加一维ans。向量长这样:

\((f_0, f_1, f_2,\dots,f_{n-1},ans,1)\)。

这样转移矩阵\(g[n+1][n+1]\)就可以被描述为:

\(\left [ \begin{matrix} & 第1列 & 第i列 & 第n列 & 第n+1列 \\第一行 & \dots & \dots & 1&0 \\ 第二行 & \dots & \dots & 0 & 0 \\ 第三行 & \dots & \dots & 0 & 0 \\ \dots \\ 第n行 & 0 & 0 & 1 & 0 \\ 第n+1行 & 0 & [s[i]=ch]*[ch!='0'] & 0 & 1\end{matrix} \right ]\)

先将矩阵进行处理,再把初始向量和矩阵相乘。\((0, 0, \dots,0, 1)*g[n+1][n+1]=(f_0, f_1, \dots,ans,1)\),答案就是\(f_0+ans\)。由于初始向量只有第n+1项是1,所以\(f_0+ans=g[n+1][0]+g[n+1][n]\)。

注意单个字符0不能被漏掉统计,因此需要记录串中的0的个数。

#include <cctype>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
const int maxk=30, maxn=40, maxl=105;
int n, r, k, zero[maxn];
char s[maxk][maxl];
struct Mat{
    int g[maxn][maxn];
}matrix[maxn], C;
void up(int &x, int y){ x+=y-r; x=(x<0?x+r:x); }
Mat& operator *(const Mat &A, const Mat &B){
    memset(C.g, 0, sizeof(C.g));
    for (int i=0; i<=n+1; ++i)
    for (int j=0; j<=n+1; ++j)
    for (int k=0; k<=n+1; ++k)
        up(C.g[i][j], 1ll*A.g[i][k]*B.g[k][j]%r);
    return C;
}

void build(int id){  //复合字符'A'+i 所对应的转移矩阵
    int len=strlen(s[id]), num;
    Mat &now=matrix[id], trans;
    for (int i=0; i<=n+1; ++i) now.g[i][i]=1;  //相当于直接让转移矩阵相乘
    for (int i=3; i<len; ++i){
        if (isdigit(s[id][i])){
            num=s[id][i]-'0';
            memset(trans.g, 0, sizeof(trans.g));
            trans.g[0][n]=trans.g[n][n]=trans.g[n+1][n+1]=1;
            for (int j=0; j<n; ++j) trans.g[j][(j*10+num)%n]=1;
            if (num) trans.g[n+1][num%n]=1;
            else up(zero[id], 1);
            now=now*trans;
        } else {
            num=s[id][i]-'A';
            now=now*matrix[num];
            up(zero[id], zero[num]);
        }
    }
}

int main(){
    scanf("%d%d%d", &n, &r, &k);
    for (int i=0; i<k; ++i) scanf("%s", s[i]);
    for (int i=k-1; ~i; --i) build(i);
    int ans=zero[0]; up(ans, matrix[0].g[n+1][0]);
    up(ans, matrix[0].g[n+1][n]);
    printf("%d\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/MyNameIsPc/p/9362107.html

时间: 2024-10-16 06:10:50

形态形成场(矩阵乘法优化dp)的相关文章

[BZOJ 1009] [HNOI2008] GT考试 【AC自动机 + 矩阵乘法优化DP】

题目链接:BZOJ - 1009 题目分析 题目要求求出不包含给定字符串的长度为 n 的字符串的数量. 既然这样,应该就是 KMP + DP ,用 f[i][j] 表示长度为 i ,匹配到模式串第 j 位的字符串个数,然后转移就是可以从第 j 位加上一个字符转移到另一个位置. 然而..我并没有写过KMP + DP,我觉得还是写AC自动机+DP比较简单..于是,尽管只有一个模式串,我还是写了AC自动机+DP. 然后就是建出AC自动机,f[i][j] 表示长度为 i ,走到节点 j 的字符串的个数.

矩阵乘法优化dp

前几天学姐说要给我们考矩乘dp和期望dp...其实我们都(也可能只有我)不会. 那只能现学了,然而学了一天突然通知不考了qwq 矩阵乘法 A矩阵为m*k,B矩阵为k*n,两矩阵相乘则得C矩阵为m*n; for (int i=1;i<=M;++i) for (int j=1;j<=N;++j) for (int k=1;k<=K;++k) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod; 矩阵乘法模板  时间复杂度为$O(N^3)$,数学一本通上

BZOJ 1875 SDOI 2009 HH去散步 矩阵乘法优化DP

题目大意:给出一张无向图,求从A到B走k步(不能走回头路)的方案数.(k <= 2^30) 思路:看到k的范围就知道是矩阵乘法了.关键是不能走回头路怎么构造.正常的方法构造点的转移不能避免这个问题,就用边来构造.只要保证不经过自己^1的边就可以保证不走回头路了. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX

2014多校第五场1010 || HDU 4920 Matrix multiplication(矩阵乘法优化)

题目链接 题意 : 给你两个n*n的矩阵,然后两个相乘得出结果是多少. 思路 :一开始因为知道会超时所以没敢用最普通的方法做,所以一直在想要怎么处理,没想到鹏哥告诉我们后台数据是随机跑的,所以极端数据是不可能会有的,而我们一开始一直在想极端数据能接受的方法......后来看了鹏哥的做法,就是把是0的地方都跳过就可以了,用矩阵保存前一个非0数的位置是多少.二师兄给我看了一个代码,人家根本没用别的优化,直接将最里层k的循环提到了最外层,然后就AC了,对此我表示无语. 1 #include <cstd

CodeForces621E 快速矩阵幂优化dp

有时些候在用快速矩阵幂优化dp的时候,它的矩阵乘法是不那么容易被具体为题目背景的意思的,大多数时候难以理解矩阵之间相乘的实际意义,正如有时候我们不知道现在在做手头这些事情的意义,但倘若是因一个目标而去做的,正如快速矩阵幂最终会计算出答案一样,我们也最终会在这些不明意义的事情中实现目标. 题意:有 bb 个格子,每个格子有 nn 个数字,各个格子里面的数字都是相同的. 求从 bb 个格子中各取一个数字, 构成一个 bb 位数, 使得这个 bb 位数模 xx 为 kk 的方案数(同一格子内相同的数字

用矩阵乘法优化递推

(有关矩阵乘法的基本规则请自行搜索) 引例:求斐波那契数列的第 n 项 mod 1000000007 的值,n <= 1018. 分析:斐波那契数列的递推式为 f(n) = f(n-1)+f(n-2),直接循环求出 f(n) 的时间复杂度是 O(n),对于题目中的数据范围显然无法承受.很明显我们需要对数级别的算法. 由于 f(n) = 1*f(n-1) + 1*f(n-2) 这样的形式很类似于矩阵的乘法,所以我们可以先把这个问题复杂化一下,将递推求解 f(n) 与 f(n-1) 的过程看作是某两

【bzoj1778】[Usaco2010 Hol]Dotp 驱逐猪猡 矩阵乘法+概率dp+高斯消元

题目描述 奶牛们建立了一个随机化的臭气炸弹来驱逐猪猡.猪猡的文明包含1到N (2 <= N <= 300)一共N个猪城.这些城市由M (1 <= M <= 44,850)条由两个不同端点A_j和B_j (1 <= A_j<= N; 1 <= B_j <= N)表示的双向道路连接.保证城市1至少连接一个其它的城市.一开始臭气弹会被放在城市1.每个小时(包括第一个小时),它有P/Q (1 <= P <=1,000,000; 1 <= Q <

hdu 4686 矩阵乘法优化递推关系

这里有一份解题报告 解题报告 这是理论知识: 点我 最主要的是构造乘法矩阵,这个是通过递推关系得到的. 有了它,求数列的第n项可以在log(n)的时间里求出来. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <set> 5 #include <algorithm> 6 #include <map> 7 #include<vect

[POJ 3150] Cellular Automaton (矩阵快速幂 + 矩阵乘法优化)

Cellular Automaton Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 3048   Accepted: 1227 Case Time Limit: 2000MS Description A cellular automaton is a collection of cells on a grid of specified shape that evolves through a number of dis