牛客多校补题 Greater and Greater bitset

Greater and Greater

题目链接

题目大意

给一个长度为n的数组a (n <= 150000)
一个长度为m的数组b (b <= 4e4)
问a中有多少个连续的子数组s满足在这里插入图片描述
也就是说问有多少个子数组 每一个数字都大于等于b中的每一个数字

题解

大佬说 这种4e4 的数据范围一看就知道是拿bitset之类的搞。。
我补题的时候刚开始的做法:
bitset<4e4>bs[1e5] 。 也就是给每一个ai 都开一个bitset 记一下b中那些数字小于等于ai 。
然后再开一个bitset cur从后往前看是否有满足条件的。。。
怎么说呢。。cur[i][j] 就是这个点跟b数组对应是第j位的时候,这个点以及这个点后面满不满足,先不看他前面的。。因为之后会弄出来。
然后 这样的话 如果cur[i][1]是1 满足的话 答案就+1
然后怎么转移呢? 就是 知道了cur[i + 1] 那么cur[i] = (cur[i + 1] >> 1 | (1 << m) ) & bs[i]
但是爆内存呢。
bs数组可以优化,bs的状态最多只有4e4中,所以bs是先预处理一下b数组。
可以再开一个数组代表b数组中最大的小于等于a的数在哪里,因为ai这里的状态就等于b的状态。
代码:

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <cmath>
#include <set>
#include <cstring>
#include <string>
#include <bitset>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef long long ll;
typedef pair<int,ll> pii;
typedef unsigned long long ull;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void wenjian(){freopen("concatenation.in","r",stdin);freopen("concatenation.out","w",stdout);}
void tempwj(){freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{bool operator()(const pii & a, const pii & b){return a.second > b.second;}};
int lb(int x){return  x & -x;}
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 150000 + 4;
const int M = 4e4+2;
int a[maxn];
int b[M];
int id[maxn];
bool cmp2(int x,int y)
{
    return a[x] < a[y];
}
bool cmp3(int x,int y)
{
    return b[x] < b[y];
}
bitset<M> bs[M];
int stemp[maxn];
int per[maxn];
bitset<M> ans;
bitset<M> tp(0);
bitset<M> t(0);
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i ++)
        scanf("%d",&a[i]);
    for (int i = 1; i <= m; i ++ )
        scanf("%d",&b[i]);
    for (int i = 1; i <= n; i ++ )
        id[i] = i;
    sort(id + 1,id + 1 + n,cmp2);
    for (int j = 1; j <= m; j ++ )
        stemp[j] = j;
    sort(stemp + 1, stemp + 1 + m,cmp3);
    for (int  i=1; i <= m; i ++ )
    {
        bs[stemp[i]] = bs[stemp[i - 1]];
        bs[stemp[i]][stemp[i]] = 1;
    }
    int k = 1;
    for (int i =1 ; i <= n; i ++ )
    {
        while(k <= m && b[stemp[k]] <= a[id[i]])
        {
            k ++ ;
        }
        k -- ;
        per[id[i]] = stemp[k];
    }
//    for (int i =1; i <= m; i ++ )
//        cout<<stemp[i]<<" ";
//    int k = 1;
//    for (int i = 1; i <= n; i ++ )
//    {
//        bs[id[i]] |= bs[id[i - 1]];
//        while(k <= m && b[stemp[k]] <= a[id[i]])
//        {
//            bs[id[i]] |= (1 << stemp[k]);
//            k ++ ;
//        }
        cout<<id[i]<<endl;
//    }
//    for (int i = 0; i <= n; i ++ )
//    {
//        cout<<bs[i]<<endl;
//    }
 
    int s =0 ;
 
    t.set(1);
    for(int i = n; i >= 1;i -- )
    {
        ans = tp >> 1;
        ans.set(m);//ac
        //ans |= (1 << m)//wa
        ans &= bs[per[i]];
        if((ans & t)!=0)
        {
            s ++ ;
        }
//        cout<<ans<<endl;
        tp = ans;
    }
 
    cout<<s<<endl;
}

1
不知道为啥这个就wa了。。烦/
感觉这个题现在会了,比赛的时候怎么也想不到,我好菜
日常自闭~~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值