版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvmaooi/article/details/82695657
没有来源。
题目大意:
给
个长度为
的01串,求不下降序列的个数。
n≤100000,k≤16
解:
这个不是正常的16维偏序。
作为一个从未见过的数据结构,这道题感觉还挺妙的。
首先很容易想到一个dp。状压一下表示当前以那个数结尾的不下降序列个数。但是这样的复杂度过不了,
如何优化这个做法?
要是把刚才那个过程看作两步:
1.计算这个数结尾的答案
2.把这个答案放进dp数组
诶,1,2步复杂度差距太大了,我们能不能平衡一下呢?
事实证明是可以的。
我们状态定义两维: 表示前八位为 ,后八位是 的子集的方案数。转移的时候只用在前八位枚举 的子集,算出答案后再枚举包含 的后八位给dp数组赋值。
居然就解决了!
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);
}