1. 程式人生 > >BZOJ5336: [TJOI2018]party

BZOJ5336: [TJOI2018]party

BZOJ5336: [TJOI2018]party

https://lydsy.com/JudgeOnline/problem.php?id=5336

分析:

  • 好題。
  • 正常的思路是設\(f[i][j][0/1/2]\)表示前\(i\)個位置,與獎章串的\(lcs\)狀態為\(j\),匹配到\(NOI\)的第幾位,然後轉移。
  • 那麼問題是這個\(lcs\)的狀態如何儲存,打個表發現這個狀態數很少,實際上也是這樣的,因為在匹配\(lcs\)的過程中,相鄰兩位\(dp\)值最多差\(1\),狀態數\(2^k\)
  • 然後就做完了,預處理出來每個狀態能轉移到的狀態即可。

程式碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
#define N 1050
#define mod 1000000007
char w[N];
int n,K;
typedef long long ll;
int tr[1<<15][3],sf[N],sg[N],cnt[1<<15];
ll f[2][1<<15][3],ans[N];
inline void upd(ll &x,ll y) {
    x=x+y; if(x>=mod) x-=mod;
}
int main() {
    scanf("%d%d%s",&n,&K,w+1);
    int i,mask=(1<<K)-1,s;
    for(s=0;s<=mask;s++) {
        for(i=1;i<=K;i++) {
            sf[i]=sf[i-1]+((s>>(i-1))&1);
        }
        for(i=1;i<=K;i++) {
            if(w[i]=='N') sg[i]=sf[i-1]+1;
            else sg[i]=max(sg[i-1],sf[i]);
            tr[s][0]|=(sg[i]-sg[i-1])*(1<<(i-1));
        }
        for(i=1;i<=K;i++) {
            if(w[i]=='O') sg[i]=sf[i-1]+1;
            else sg[i]=max(sg[i-1],sf[i]);
            tr[s][1]|=(sg[i]-sg[i-1])*(1<<(i-1));
        }
        for(i=1;i<=K;i++) {
            if(w[i]=='I') sg[i]=sf[i-1]+1;
            else sg[i]=max(sg[i-1],sf[i]);
            tr[s][2]|=(sg[i]-sg[i-1])*(1<<(i-1));
        }
    }
    f[0][0][0]=1;
    for(i=0;i<n;i++) {
        int i0=i&1,i1=(i+1)&1;
        for(s=0;s<=mask;s++) {
            //O/I->N
            upd(f[i1][tr[s][0]][1],f[i0][s][0]);
            //O/I->O
            upd(f[i1][tr[s][1]][0],f[i0][s][0]);
            //O/I->I
            upd(f[i1][tr[s][2]][0],f[i0][s][0]);
            //N->N
            upd(f[i1][tr[s][0]][1],f[i0][s][1]);
            //N->O
            upd(f[i1][tr[s][1]][2],f[i0][s][1]);
            //N->I
            upd(f[i1][tr[s][2]][0],f[i0][s][1]);
            //NO->N
            upd(f[i1][tr[s][0]][1],f[i0][s][2]);
            //NO->O
            upd(f[i1][tr[s][1]][0],f[i0][s][2]);
        }
        memset(f[i0],0,sizeof(f[i0]));
    }
    for(i=0;i<=mask;i++) cnt[i]=cnt[i>>1]+(i&1);
    for(s=0;s<=mask;s++) for(i=0;i<3;i++) upd(ans[cnt[s]],f[n&1][s][i]);
    for(i=0;i<=K;i++) printf("%lld\n",ans[i]);
}