题意:

给定N (1 ≤ N ≤ 10)个长度不超过6的单词,求由大写字母组成长度为L的包含至少一个给定单词的字符串有多少种,答案 mod 10007,(1 ≤ L ≤ 10^6)。

题解:

这个题最早是在一个关于trie图的论文中看到了,最近jzh又讲到了这个题,于是就把它做了~

大致有两种做法,两种方法都需要矩阵乘法加速

1、trie图中的dp

2、直接人工减少转移数量

具体做法点击这里

大致思路就是将不可能构成单词的前缀合成一类,然后胡搞就行了。

View Code

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <string>
  5 #include <cstdlib>
  6 #include <algorithm>
  7 #include <map>
  8
  9 #define N 60
 10 #define SIZE 70
 11 #define mod 10007
 12
 13 using namespace std;
 14
 15 map<string,int> mp;
 16
 17 int n,cnt,res,m;
 18 string str[N],prefix[SIZE];
 19
 20 struct MT
 21 {
 22     int x,y;
 23     int mt[SIZE][SIZE];
 24 }zy,ans;
 25
 26 inline MT operator *(MT a,MT b)
 27 {
 28     MT c; memset(c.mt,0,sizeof c.mt);
 29     c.x=a.x; c.y=b.y;
 30     for(int i=1;i<=c.x;i++)
 31         for(int j=1;j<=c.y;j++)
 32             for(int k=1;k<=a.y;k++)
 33             {
 34                 c.mt[i][j]+=a.mt[i][k]*b.mt[k][j];
 35                 if(c.mt[i][j]>=mod) c.mt[i][j]%=mod;
 36             }
 37     return c;
 38 }
 39
 40 inline void read()
 41 {
 42     mp.clear();
 43     for(int i=1;i<=n;i++)
 44     {
 45         cin>>str[i];
 46         mp[str[i]]=520;
 47     }
 48 }
 49
 50 inline bool check(string x)//检查x是否是合法的前缀
 51 {
 52     string::size_type pos;
 53     for(int i=1;i<=n;i++)
 54     {
 55         pos=x.find(str[i]);
 56         if(pos!=x.npos) return false;
 57     }
 58     return true;
 59 }
 60
 61 inline void get_det()
 62 {
 63     memset(zy.mt,0,sizeof zy.mt);
 64     cnt=0;
 65     for(int i=1;i<=n;i++)
 66     {
 67         string tmp;
 68         for(int j=0;j<str[i].length();j++)
 69         {
 70             tmp.push_back(str[i][j]);
 71             if(check(tmp)&&mp[tmp]==0)
 72             {
 73                 mp[tmp]=++cnt;//前缀字符串的映射
 74                 prefix[cnt]=tmp;//前缀字符串
 75             }
 76         }
 77     }
 78     zy.x=zy.y=cnt+1;
 79
 80     string tmp;
 81     for(int i=1;i<=cnt;i++)
 82         for(int j=0;j<26;j++)
 83         {
 84             tmp=prefix[i]; tmp.push_back(j+'A');
 85             for(int k=tmp.length();k>=0;k--)
 86             {
 87                 if(k==0)
 88                 {
 89                     zy.mt[cnt+1][mp[prefix[i]]]++;//不存在后缀是已知的前缀
 90                     break;
 91                 }
 92                 else
 93                 {
 94                     string tp;
 95                     for(int p=tmp.length()-k;p<tmp.length();p++)
 96                         tp.push_back(tmp[p]);
 97                     if(mp[tp]==520) break;//出现单词,不合法
 98                     else if(mp[tp]!=0) {zy.mt[mp[tp]][mp[prefix[i]]]++;break;}//存在最大的后缀是已知的前缀
 99                 }
100             }
101         }
102     for(int i=0;i<26;i++)
103     {
104         string sy;
105         sy.push_back(i+'A');
106         if(mp[sy]==0) zy.mt[cnt+1][cnt+1]++;
107         else if(mp[sy]==520) continue;
108         else zy.mt[mp[sy]][cnt+1]++;
109     }
110
111     ans.x=cnt+1; ans.y=1;
112     memset(ans.mt,0,sizeof ans.mt);
113     ans.mt[cnt+1][1]=1;
114 }
115
116 inline int qs(int a,int b)
117 {
118     int res=1;
119     while(b)
120     {
121         if(b&1) res=(res*a)%mod;
122         a=(a*a)%mod;
123         b>>=1;
124     }
125     return res;
126 }
127
128 inline void go()
129 {
130     get_det();
131     res=qs(26,m);
132     while(m)
133     {
134         if(m&1) ans=zy*ans;
135         zy=zy*zy;
136         m>>=1;
137     }
138
139     int tmp=0;
140     for(int i=1;i<=cnt+1;i++) tmp=(tmp+ans.mt[i][1])%mod;
141     res-=tmp;
142     printf("%d\n",(res+mod)%mod);
143 }
144
145 int main()
146 {
147     while(scanf("%d%d",&n,&m)!=EOF) read(),go();
148     return 0;
149 }

转载于:https://www.cnblogs.com/proverbs/archive/2013/02/17/2914168.html

SPOJ 1676 矩阵乘法+DP相关推荐

  1. 【BZOJ2326】【HNOI2011】数学作业 [矩阵乘法][DP]

    数学作业 Time Limit: 10 Sec  Memory Limit: 128 MB [Submit][Status][Discuss] Description Input 输入文件只有一行为用 ...

  2. 【BZOJ4818】【SDOI2017】序列计数 [矩阵乘法][DP]

    序列计数 Time Limit: 30 Sec  Memory Limit: 128 MB [Submit][Status][Discuss] Description Alice想要得到一个长度为n的 ...

  3. [学习笔记]矩阵乘法及其优化dp

    1.定义: $c[i][j]=\sum a[i][k]\times b[k][j]$ 所以矩阵乘法有条件,(n*m)*(m*p)=n*p 即第一个矩阵的列数等于第二个矩阵的行数,否则没有意义. 2.结 ...

  4. 【bzoj4870】[Shoi2017]组合数问题 dp+快速幂/矩阵乘法

    题目描述 输入 第一行有四个整数 n, p, k, r,所有整数含义见问题描述. 1 ≤ n ≤ 10^9, 0 ≤ r < k ≤ 50, 2 ≤ p ≤ 2^30 − 1 输出 一行一个整数 ...

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

    形态形成场(矩阵乘法优化dp) 短信中将会涉及前\(k\)种大写字母,每个大写字母都有一个对应的替换式\(Si\),替换式中只会出现大写字母和数字,比如\(A→BB,B→CC0,C→123\),代表 ...

  6. BZOJ 1444 [JSOI2009]有趣的游戏 (AC自动机、概率与期望DP、矩阵乘法)

    诶这题洛谷居然没有??? 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1444 题解: 我见到主要有两种做法. 一是矩阵乘法.设\(d ...

  7. BZOJ 3329 Xorequ (数位DP、矩阵乘法)

    BZOJ 3329 Xorequ (数位DP.矩阵乘法) 手动博客搬家: 本文发表于20181105 23:18:54, 原地址https://blog.csdn.net/suncongbo/arti ...

  8. 【学习笔记】浅谈广义矩阵乘法——动态DP

    文章目录 广义矩阵乘法 动态DP 例题:洛谷4719 以下内容是本人做题经验,如有雷同,纯属抄袭:如有不对,纯属不懂,还请指正 广义矩阵乘法 众所周知,矩阵满足乘法交换律,前一个矩阵的列必须是后一个矩 ...

  9. 【2019牛客暑期多校训练营(第二场)- E】MAZE(线段树优化dp,dp转矩阵乘法,线段树维护矩阵乘法)

    题干: 链接:https://ac.nowcoder.com/acm/contest/882/E?&headNav=acm 来源:牛客网 Given a maze with N rows an ...

最新文章

  1. oracle 分区表的建立方法
  2. 深入理解Python字符编码--转
  3. 大数据体系【协议】系列-1:gossip协议
  4. Oracle(3)——Oracle图形界面工具创建数据库
  5. IKVM:java代码c#调用
  6. 少儿编程几种语言_您使用了几种编程语言?
  7. SQL Server 2014 导入Excel
  8. Atiitt 使用java语言编写sql函数或存储过程
  9. 人去楼空 暴风影音倒闭 今后将成为历史?
  10. GD32VF103学习笔记(1)
  11. 平面方程(Plane Equation)求解方法
  12. 键盘鼠标是计算机标准输入输出设备,输入输出设备.ppt
  13. ARX中非模态对话框
  14. 2019年暑期GooGle SWE 凉经
  15. 第十九章《类的加载与反射》第3节:反射
  16. 什么是通达信接口函数
  17. Debian11之 RKE2 部署 K8S 集群
  18. GPS研究---GPS 系统的组成
  19. 常用CDK生成Java算法(大数异或)
  20. 〖教程〗LadonGO免杀Win10 Defender

热门文章

  1. 超速问题的c语言编程,超速行驶问题--精选.doc
  2. azure git怎么使用_Azure(一)Azure Traffic Manager为我们的Web项目提供负载均衡
  3. 如果__name__ =='__main__':在Python中怎么办?
  4. 怎样看虚拟主机的服务器,虚拟主机怎么查看服务器类型
  5. 远控免杀专题(22)-SpookFlare免杀
  6. 242. 有效的字母异位词 golang
  7. 744. 寻找比目标字母大的最小字母 golang
  8. 本能富可敌国,最后却选择拯救世界!Bram的Vim和乌干达儿童
  9. Xshell链接不上云服务器的解决方案
  10. 归并排序概念及其实现