Data structure you've never heard of(枚举+dp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvmaooi/article/details/82695657

没有来源。

题目大意:

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);
}

猜你喜欢

转载自blog.csdn.net/lvmaooi/article/details/82695657
今日推荐