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 }
  • 相关阅读:
    Codeforces467C George and Job
    Codeforces205E Little Elephant and Furik and RubikLittle Elephant and Furik and Rubik
    Codeforce205C Little Elephant and Interval
    51nod1829 函数
    51nod1574 排列转换
    nowcoder35B 小AA的数列
    Codeforce893E Counting Arrays
    gym101612 Consonant Fencity
    CodeForces559C Gerald and Giant Chess
    CodeForces456D A Lot of Games
  • 原文地址:https://www.cnblogs.com/proverbs/p/2914168.html
Copyright © 2011-2022 走看看