2020牛客暑期多校训练营Greater and Greater(dp,bitset优化)

Greater and Greater

题目描述

在这里插入图片描述

输入描述:

在这里插入图片描述

输出描述:

在这里插入图片描述

示例1

输入

6 3
1 4 2 8 5 7
2 3 3

输出

2

说明

在这里插入图片描述

题目大意

给定2个数列a和b,其中alen>=blen,求b有多少种可能与a的长度为blen的子串匹配,匹配的条件是对于任意的i,满足ai>=bi,则匹配。

分析

一个错的思路

许多人拿到这题,就会想到魔改KMP,嗯我也是这么WA过来的。随手就这么一段代码,于是喜提WA一枚(其实不止,大概有5枚)。

那么问题来了,KMP到底为什么不能用呢。
看官可以试试下面这组数据:
a:1 1 2 2 1 2 1 1 2 1 1
b:2 1
如果你的答案是3(正确的是4才对),那么就应该知道为什么了。下面不再赘述。

一个对的思路(假)

DP!对就是DP,设dp[i][j]表示对于第i位的ai,b在第j位与之匹配,且之后的均已匹配,则dp[i][j]=1,否则=0。

即dp[i][j]表示ai—i+blen-j与bj—j+blen匹配。

则有dp转移式: dp[i][j]=dp[i-1][j-1]&(a[i]>=b[j]);

由此可知,答案存在dp[i][1]中,最后累加下即可。

但是,算下复杂度又发现不对,O(nm)啊,这不炸了吗?居然有dp会炸,那怎么办呢?

一个真的对的思路

其实上面说的已经不假了,就是用dp做的,观察这个dp,发现它只存了01两种值,此时我们可以用到一个STL:
bitset
bitset是一个01数组,可以像整数那样位运算,虽然还是慢,但是可以加速到原来的1/32,(机子好的老板64位则可以1/64),刚好卡过时间(从未见过如此厚颜无耻之操作)。
接下来是bitset的一些用法:

bitset<40010> bt;//定义一个长为40010的名为bt的bitset
bitset<40010> bt[MAXN]//如同vector一样,也可以定义成数组的bitset
bt.set()//把bitset bt的所有值赋为1
bt.reset()//赋为0
bt.set(pos)//把pos位的赋为1,reset同
bt.count()//数有几个1

OK,有了bitset这一神器,可以把dp转成bitset了。
dp[i][j]就是bti[j]
dp[i-1][j-1]就是bti-1>>1,(这里值得注意的是,bitset的存的方向是反的)

所以bti=((bti>>1)|(1<<m))&(a[i]>=b[j])
这下麻烦了,我不知道j了啊。所以a[i]>=b[j]要预处理,再用二分查找函数快速找到。

预处理这一部分建议看下官方题解,写的蛮详细的。

好了话不多说,上DM。

代码

#include<bits/stdc++.h>
#define ll long long
#define inf 1<<30
using namespace std;
const int MAXN=150010;
const int MAXM=40010;
struct node{
    int v,p;
}a[MAXN],b[MAXM];
bool cmp(node x,node y){return x.v<y.v;}
bitset<40010> s[MAXM],cur,I;
int main()
{
    int n,m,ans=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i].v);
    for(int i=1;i<=m;i++) scanf("%d",&b[i].v),b[i].p=i;
    sort(b+1,b+1+m,cmp);
    for(int i=1;i<=m;i++){
        s[i]=s[i-1];
        s[i].set(b[i].p);
    }//预处理
    I.set(1);//好像没什么用,各位看官帮蒟蒻想一下
    cur.set();
    for(int i=1;i<=n;i++){
        int pos=upper_bound(b+1,b+1+m,a[i],cmp)-b-1;//用二分查找函数
        cur=(((cur<<1)|I)&s[pos]);
        if(i>=m&&cur[m]) ans++;
    }
    printf("%d\n",ans);
}//cur即dp,官方用了cur,看题解时避免麻烦就用了cur了

END

蒟蒻写得不好,dalao见谅。
这个大佬的题解好,可以看下。

猜你喜欢

转载自blog.csdn.net/zhangchizc/article/details/107406023
今日推荐