• [2020牛客暑期多校训练营(第二场)Greater and Greater]


    2020牛客暑期多校训练营(第二场)Greater and Greater

    题目大意:

    给你一个n大小的序列A和一个m大小的序列B,问A这个序列有多少个m大小的子区间满足(假设子区间为S) 任意 (1<=i<=m)(S_i>B_i)

    题解:

    这个官方题解讲的很清楚了,但是我并没有看懂。

    • 首先考虑 (n*m) 的做法。

      (dp[i][j]) 表示从后面往前匹配,A串匹配到了第 (i) 位,B串匹配到了第 (j) 位,是否完全匹配。

      状态转移方程 (dp[i][j]=(A_i>=B_j)&dp[i+1][j+1]) 这个 $dp[i][j]=0 ,or,1 $

    • 然后考虑 (bitset) 优化 (dp) ,因为每一位只有0或者1,而且 (dp[i]) 只与 (dp[i+1]) 有关系,所以考虑一起转移,定义一个 (bitset)(dp[i]) 表示A串从后往前匹配到了第 (i) 位,因为 (dp[i]) 的数据类型是 (bitset) ,所以其中第 (j) 位如果是1,表示 (dp[i][j]=1)

    • 再考虑 (A_i>=B_i) ,因为要一起转移,所以对于每一个 (A_i) 都要同时判断和 (B_j) 的大小。 这就意味着要求出每一个 (i) 和B串所有位置的关系,这个也可以用一个 (bitset) 来存。

    • 这个存也是有一点点小技巧的,如果我们把 B 串从小到大排个序,那么最多是不是就只能分成 (m+1) 份,所以说最多只有 (m+1) 种不同的 (bitset)

    • 先把这个 (m+1) 种不同的 (bitset) 存下来,然后对于每一个 (A_i) 我先二分判断它在排序之后的 (B) 串的位置,然后再选择要用哪个 (bitset) 。(虽然 (m*m) 很大,但是因为 (bitset) 只占一个 (bit) 所以并没有超空间)

    • 最后就是转移方程了,我一直 (S_i) (表示 (A_i)(biset)),已知 (dp[i+1])

      转移方程 (dp[i]=S_i&(dp[i+1]<<1)) 这个为什么是 (dp[i+1]<<1) 应该很好理解把?

      因为 (dp[i][j]) 是需要 (dp[i+1][j+1]) 来判断的。

      但是这样就是对的转移方程了吗?

      其实还差一点点,因为对于 (dp[i][m]) 是只需要 (A_i>B_m) 即可,所以 (dp[i+1]) 往前挪一位之后空下来的那一位应该要是1才行,所以 (dp[i+1]<<1) 之后还要按位与一个 (1<<m)

      所以最终的转移方程就是:

      (dp[i]=S_i&((dp[i+1]<<1)|(1<<m)))

    #include <bits/stdc++.h>
    #define debug(x) printf("debug:%s=%d
    ",#x,x);
    //#define debug(x) cout << #x << ": " << x << endl;
    using namespace std;
    typedef long long ll;
    const int maxn = 2e5+10;
    const int M = 4e4+10;
    bitset<M>dp[2];
    bitset<M>S[M];
    int a[maxn],v[M],p[M];
    bool cmp(int a,int b){
        return v[a]<v[b];
    }
    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",&v[i]);
            p[i]=i;
        }
        sort(p+1,p+1+m,cmp);
        sort(v+1,v+1+m);
        for(int i=1;i<=m;i++) {
            S[i]=S[i-1],S[i].set(p[i]-1);
        }
        bitset<M> now;now.reset();now.set(m-1);
        bitset<M> base;base.reset();base.set(0);
        int ans=0,id=0;
        for(int i=n;i>=1;i--){
            int t = upper_bound(v+1,v+1+m,a[i])-v-1;
            dp[id^1]=S[t]&((dp[id]>>1)|now);
            if((dp[id^1]&base).count())  ans++;
            id^=1;
            dp[id^1]=dp[id];
        }
        printf("%d
    ",ans);
        return 0;
    }
    /*
    
    6 4
    8 6 4 5 6 5
    7 4 6 3
    
    */
    
    
    
    
    
    
    
  • 相关阅读:
    BUCK/BOOST电路原理分析
    boost升压电路原理
    NPN/PNP和N沟道/P沟道负载的接法
    常用电源芯片记录
    LDO和BUCK降压稳压器对比
    some nets were not able to be matched
    Altium PCB布局时快速摆放元件的技巧
    树莓派+android things+实时音视频传输demo之遥控小车
    野狗产品与价格
    librtmp将本地FLV文件发布到RTMP流媒体服务器
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13320776.html
Copyright © 2020-2023  润新知