zoukankan      html  css  js  c++  java
  • SPOJ 1676 矩阵乘法+DP

    题意:

    给定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 }
  • 相关阅读:
    python学习(二十三) String(下) 分片和索引
    python学习(二十二) String(上)
    微服务网关
    【转】linux 软连接 硬链接
    设计模式--观察者模式
    设计模式--策略模式
    ubuntu-server 安装redis
    【转】linux的hostname修改详解
    【转】ftp的两种模式
    【转】linux下find查找命令用法
  • 原文地址:https://www.cnblogs.com/proverbs/p/2914168.html
Copyright © 2011-2022 走看看