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

没有来源。

题目大意:

n n 个长度为k的01串,求不下降序列的个数。
n≤100000,k≤16










解:

这个不是正常的16维偏序。
作为一个从未见过的数据结构,这道题感觉还挺妙的。

首先很容易想到一个dp。状压一下表示当前以那个数结尾的不下降序列个数。但是这样的复杂度过不了,O(n2k)
如何优化这个做法?
要是把刚才那个过程看作两步:
1.计算这个数结尾的答案
2.把这个答案放进dp数组

诶,1,2步复杂度差距太大了,我们能不能平衡一下呢?
事实证明是可以的。

我们状态定义两维: f(i,j) f ( i , j ) 表示前八位为 i i ,后八位是j的子集的方案数。转移的时候只用在前八位枚举 i i 的子集,算出答案后再枚举包含j的后八位给dp数组赋值。

居然就解决了! O(n2k2) 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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值