zoukankan      html  css  js  c++  java
  • 4572: [Scoi2016]围棋 轮廓线DP KMP

    国际惯例的题面:

    这种题目显然DP了,看到M这么小显然要状压。
    然后就是具体怎么DP的问题。
    首先我们可以暴力状压上一行状态,然后逐行转移。复杂度n*3^m+3^(m*2),显然过不去。

    考虑状态的特殊性,每个位置是黑子白子我们并不关心,我们只关心与模板的匹配情况。
    于是我们可以f(i,S,x,y)表示我们决策到i行j列,S表示上一行哪些位置和这一行哪些位置能与模板第一行完全匹配,x表示当前行与模板第一行匹配长度,y表示当前行与模板第二行匹配长度。
    转移的话就枚举当前行下一个位置填什么颜色棋子(或空着)即可,复杂度n*(3^m)m*c*c*(2^m)*3,显然也凉了。
    但是,我们发现如果一行能与模板第一行完全匹配,显然这个匹配位置最少在这一行的位置c。这样就能把次数中的m变成m-c+1。
    这样仍旧不能AC。因为这只是普通的状压DP,显然有很多无用状态。

    轮廓线DP的巧妙之处在于:因为采用了逐格转移,它压缩的状态可以部分是上一行的,部分是这一行的。
    于是我们可以f(i,j,S,x,y)表示我们决策到i行j列,S表示上一行>=j的哪些位置和这一行<j的哪些位置能与模板第一行完全匹配,x表示当前行与模板第一行匹配长度,y表示当前行与模板第二行匹配长度。
    我们枚举下一个格子填什么颜色的棋子,进行转移即可。复杂度n*m*3(m-c+1)*(c^2)*3。

    代码:

     1 #include<cstdio>
     2 typedef long long int lli;
     3 const int maxs=1<<10,maxl=13;
     4 const int mod=1e9+7;
     5 
     6 char ina[maxl],inb[maxl];
     7 int faila[maxl],failb[maxl],nxta[maxl][3],nxtb[maxl][3];
     8 int f[2][maxs][maxl][maxl];
     9 int n,m,c,q,full,mask,cur;
    10 lli ans;
    11 
    12 inline lli fastpow(lli base,int tim) {
    13     lli ret = 1;
    14     while(tim) {
    15         ret = ( tim & 1 ) ? ret * base % mod : ret;
    16         base = ( tim >>= 1 ) ? base * base % mod : base;
    17     }
    18     return ret;
    19 }
    20 inline char gid(char c) {
    21     return c == 'W' ? 0 : c == 'B' ? 1 : 2;
    22 }
    23 inline void kmp(char* s,int* fail,int nxt[maxl][3]) {
    24     for(int i=1;i<=c;i++) s[i] = gid(s[i]);
    25     fail[0] = fail[1] = 0;
    26     for(int i=2,j=0;i<=c;i++) {
    27         while( j && s[j+1] != s[i] ) j = fail[j];
    28         fail[i] = ( j += ( s[j+1] == s[i] ) );
    29     }
    30     for(int i=0;i<=c;i++) for(int cur=0;cur<3;cur++) {
    31         int k = i;
    32         while( k && s[k+1] != cur ) k = fail[k];
    33         nxt[i][cur] = ( k += ( s[k+1] == cur ) );
    34     }
    35 }
    36 
    37 inline void reset(int f[maxs][maxl][maxl]) {
    38     for(int i=0;i<full;i++) for(int j=0;j<=c;j++) for(int k=0;k<=c;k++) f[i][j][k] = 0;
    39 }
    40 
    41 int main() {
    42     scanf("%d%d%d%d",&n,&m,&c,&q) , full = 1 << ( m - c + 1 ) , mask = full - 1;
    43     while(q--) {
    44         scanf("%s%s",ina+1,inb+1) , kmp(ina,faila,nxta) , kmp(inb,failb,nxtb) , reset(f[cur=0]) , f[cur][0][0][0] = 1;
    45         for(int i=1;i<=n;i++) {
    46             reset(f[cur^=1]);
    47             for(int j=0;j<full;j++) for(int pa=0;pa<c;pa++) for(int pb=0;pb<c;pb++) f[cur][j][0][0] = ( f[cur][j][0][0] + f[cur^1][j][pa][pb] ) % mod;
    48             for(int j=1;j<=m;j++) {
    49                 reset(f[cur^=1]);
    50                 for(int sta=0;sta<full;sta++) for(int pa=0;pa<c;pa++) for(int pb=0;pb<c;pb++) if( f[cur^1][sta][pa][pb] )for(int sel=0;sel<3;sel++) {
    51                     int nowa = nxta[pa][sel] , nowb = nxtb[pb][sel] , nowsta = sta;
    52                     if( j >= c ) nowsta &= ( mask ^ ( 1 << ( j - c ) ) ); // clear bit j - c .
    53                     if( nowa == c ) nowsta ^= 1 << ( j - c ) , nowa = faila[nowa]; // set bit j - c .
    54                     if( nowb == c ) {
    55                         if( sta & ( 1 << ( j - c ) ) ) continue; // paired .
    56                         else nowb = failb[nowb];
    57                     }
    58                     f[cur][nowsta][nowa][nowb] = ( f[cur][nowsta][nowa][nowb] + f[cur^1][sta][pa][pb] ) % mod;
    59                 }
    60             }
    61         }
    62         ans = fastpow(3,n*m);
    63         for(int sta=0;sta<full;sta++) for(int pa=0;pa<c;pa++) for(int pb=0;pb<c;pb++) ans = ( ans - f[cur][sta][pa][pb] + mod ) % mod;
    64         printf("%lld
    ",ans);
    65     }
    66     return 0;
    67 }
    View Code

     
    もうこの手を 離さないから笑い合えるよ
    我已不会再放手 所以一起欢笑吧
    またこの場所から ふたり歩き出そう この道を
    让我们再次从这里出发 踏上这条道路
    朝の澄んだ陽射し 夜空に瞬く星
    清晨干净的阳光 夜空中闪烁的繁星
    たわいもないこと 分け合って感じるぬくもり
    不管多琐碎的事 互相分享的温暖
    ひとりきりの記憶 思い出してしまうたび
    每当我回想起独自一人的记忆
    いつも鄰で 撫でてくれてたから 笑えた
    你总在我身边 抚摸着我朝我微笑

  • 相关阅读:
    扩欧(exgcd讲解)
    Django组件之forms
    Django组件之用户认证
    Django之中间件
    Django之cookie与session
    Django组件之分页器
    Django之Ajax
    Django之模型层2
    Django之模型层
    Django之模板层
  • 原文地址:https://www.cnblogs.com/Cmd2001/p/8988126.html
Copyright © 2011-2022 走看看