欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2020牛客多校 G - Greater and Greater 动态规划+bitset优化

程序员文章站 2022-04-02 19:02:56
...

题目链接:
https://ac.nowcoder.com/acm/contest/5667/G

  思路与官方题解相同,只是描述方式不同。

  设dpi,jdp_{i,j}表示子序列[Ai,Ai+mj][A_i,A_{i+m-j}]与子序列[Bj,Bm][B_j,B_m]是否匹配,即k[0,mj]Ai+kBj+k\forall k \in [0,m-j],A_{i+k}\ge B_{j+k}匹配则为11,不匹配则为00。可以想到答案就是j=1j=1时子序列[Ai,Ai+m1][A_i,A_{i+m-1}]与子序列[B1,Bm][B_1,B_m]匹配的总数,即ans=i=1nm+1dpi,1ans=\sum_{i=1}^{n-m+1}{dp_{i,1}}

  考虑dpdp的转移方程dpi,j=dpi+1,j+1&(AiBj)dp_{i,j}=dp_{i+1,j+1}\&(A_i\ge B_j)即若想子序列[Ai,Ai+mj][A_i,A_{i+m-j}]与子序列[Bj,Bm][B_j,B_m]匹配,则需要子序列[Ai+1,Ai+mj][A_{i+1},A_{i+m-j}]与子序列[Bj+1,Bm][B_{j+1},B_m]匹配,且AiBjA_i\ge B_j

  可以想到,这个转移的计算复杂度是O(nm)O(nm),约6e96e9,超时,也超空间。

  由于所有dpdp值都是0或1,可以采用bitset优化,这样复杂度就变为O(nmw)O(\frac{nm}{w})w=3264w=32或64,处于可以接受的范围。

  设bitdpi[j]=dpi,jbitdp_i[j]=dp_{i,j},这样有关jj的操作,都可以用bitset优化。可以用右移将jj向前移动一位,使得bitdpi+1[j+1]bitdp_{i+1}[j+1]转移到bitdpi[j]bitdp_i[j]。对于AiBjA_i\ge B_j的判断,可以预处理一个长度为mm的bitset表SiS_iSi[j]=(AiBj)S_i[j]=(A_i\ge B_j),这样,转移式就优化为bitdpi=(bitdpi+1>>1(1<<m))&Sibitdp_i=(bitdp_{i+1}>>1|(1<<m))\&S_i
  计算SiS_i时,把mmBjB_j排序后,那么每个AiA_i只会插在这些BjB_j中间或两边,因此最多只有m+1m+1SiS_i(从全是00的情况,到全是11的情况)。第jjSiS_i,就是在前一种SiS_i的基础上在第jj大的BjB_j位置上从00变为11。这样就可以在O(m2w)O(\frac{m^2}{w})的复杂度内预处理完SiS_i

代码如下(不是我写的):

#include<bits/stdc++.h>

using namespace std;

const int MAXN=2e5+10,MAXM=4e4+10;
int n,m,ans,a[MAXN],b[MAXM],pos[MAXN];
bitset<MAXM> s[MAXM],cur,w;

bool cmp(int x,int y){return b[x]<b[y];}

int main()
{
    scanf("%d%d",&n,&m);w[m]=1;
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    for(int i=1;i<=m;i++) scanf("%d",b+i),pos[i]=i;
    sort(pos+1,pos+1+m,cmp);
    sort(b+1,b+1+m);
    for(int i=1;i<=m;i++) s[i]=s[i-1],s[i][pos[i]]=1;
    for(int i=n;i>=1;i--)
	{
        int d=upper_bound(b+1,b+1+m,a[i])-b-1;
        cur=(((cur>>1)|w)&s[d]);
        if(cur[1]) ans++;
    }
    printf("%d\n",ans);
}