1. 程式人生 > >Data structure you've never heard of(列舉+dp)

Data structure you've never heard of(列舉+dp)

沒有來源。

題目大意:

n 個長度為 k 的01串,求不下降序列的個數。
n≤100000,k≤16











解:

這個不是正常的16維偏序。
作為一個從未見過的資料結構,這道題感覺還挺妙的。

首先很容易想到一個dp。狀壓一下表示當前以那個數結尾的不下降序列個數。但是這樣的複雜度過不了, O ( n 2 k )
如何優化這個做法?
要是把剛才那個過程看作兩步:
1.計算這個數結尾的答案
2.把這個答案放進dp陣列

誒,1,2步複雜度差距太大了,我們能不能平衡一下呢?
事實證明是可以的。

我們狀態定義兩維: f ( i , j ) 表示前八位為 i ,後八位是 j 的子集的方案數。轉移的時候只用在前八位列舉 i 的子集,算出答案後再列舉包含 j 的後八位給dp陣列賦值。

居然就解決了! O ( n 2 k 2 )

orz根本想不到好吧。

#include<iostream>
#include<cstdio>
#include<cstring>
#define mod 1000000007
using namespace std;

long long f[256][256],ans;
char s[25];
int n,k,t;

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        long long st=1;t=0;
        scanf("%s",s+1);
        for(int j=1;j<=k;j++)
          if(s[j]=='1')
            t+=(1<<(k-j));
        for(int j=0;j<=255;j++)
          if((j&(t>>8))==j)
            st=(st+f[j][t&255])%mod;
        ans=(ans+st)%mod;
        for(int j=0;j<=255;j++)
          if(((t&255)&j)==(t&255))
            f[t>>8][j]=(f[t>>8][j]+st)%mod;
    }
    printf("%lld",ans);
}