题解/算法 {5726. 连续子序列}

题解/算法 {5726. 连续子序列}

@LINK: https://www.acwing.com/problem/content/description/5729/;

sum[x] = A[0^...^x], 因为A[l^...^r] = sum[r] ^ sum[l-1], 因此 对于当前的r 我们将0, sum[0,1,...,r-1]都放入Trie树里
然后此时根据sum[r] 去树里查询, 此时 就很考察你的逻辑思维能力了 不多说了 总之是分情况讨论 即比如当前查询的是x(他是0/1) 然后此时可能0,1分支都存在 也可能只有1个存在, 此时很容易思路乱 一个核心思路是: 我们始终令当前的k < K 一旦比如你要走的分支 和x不同 此时会导致k += ?增加 那么一旦k >= K就终止, 这样的话 即使01两个分支都存在: @IF(当(k+?) >= K){即此时x^1这个分支不用走 直接把他的prefixCount累加答案即可, 然后走x分支 他不影响k的值}–@ELSE{这个情况是最最难的 此时你一定是走x^1这个分支 换句话说 答案只可能在x^1这个分支 x这个分支一定没有答案 这是因为x + (1<<b) < K 那么x + (1<<bi)之和 (其中bi<b) 也一定 < K 因此你只需要走x^1这个分支};

int k = 0;
for( int len = 0; len <= Len; ++len){
    //>< `curNode`代表`_str.substr(0,len)`这个字符串;
    ASSERT_( k < K);
    if( len < Len){
        int id = ((_a>> (Len-1-len)) & 1);
        vector<int> nex;
        FOR_( son, 0, 1){
            if( curNode->SonPtr[son] != nullptr){ nex.push_back(son);}
        }
        if( nex.size()==0){ return ANS;}
        else if( nex.size() == 1){
            k += ( (nex.front()==id ? 0:1) << (Len-1-len));
            curNode = curNode->SonPtr[ nex.front()];
            if( k >= K){
                ANS += curNode->PrefixCount;
                return ANS;
            }
        }
        else{
            if( (k + (1<<(Len-1-len))) >= K){
                ANS += curNode->SonPtr[ id^1]->PrefixCount;
                curNode = curNode->SonPtr[id];
            }
            else{
                k += (1<<(Len-1-len));
                curNode = curNode->SonPtr[id^1];
            }
        }
    }
}

上面代码是对的, 但是很可惜… 他超时了 你怎么优化都超时 可能把现在的指针版本改成是数组下标方式 应该就可以了(不知道 没试过 以后看有没有必要 数组下标版本是不是各方面都比指针版本要好吖?)

一个补救措施是 你把vector<int> nex给去掉把, 因为这个题常数确实太大了 N=1e6 * 30 = 3e7 太大了 是可以把nex给去掉 直接用两个int变量来替代 这也说明容器确实开销大; (同时你也还需要优化Trie 即普通优化 把Assert去掉)

int k = 0;
for( int len = 0; len <= Len; ++len){
    //>< `curNode`代表`_str.substr(0,len)`这个字符串;
    ASSERT_( k < K);
    if( len < Len){
        int id = ((_a>> (Len-1-len)) & 1);
        int cont = 0, tar;
        FOR_( son, 0, 1){
            if( curNode->SonPtr[son] != nullptr){ ++ cont; tar = son;}
        }
        if( cont==0){ return ANS;}
        else if( cont == 1){
            k += ( (tar==id ? 0:1) << (Len-1-len));
            curNode = curNode->SonPtr[ tar];
            if( k >= K){
                ANS += curNode->PrefixCount;
                return ANS;
            }
        }
        else{
            if( (k + (1<<(Len-1-len))) >= K){
                ANS += curNode->SonPtr[ id^1]->PrefixCount;
                curNode = curNode->SonPtr[id];
            }
            else{
                k += (1<<(Len-1-len));
                curNode = curNode->SonPtr[id^1];
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值