zoukankan      html  css  js  c++  java
  • [CF1246F]Cursor Distance

    题目链接

    题意

    光标只能使用“跳到下一个字符 $alpha$”和“跳到上一个字符 $alpha$”这两种命令来移动,求一个字符串中任意两个位置间移动的最短命令长度和。

    题解

    首先把操作反序,发现一次反操作就是把光标移动回在上一个和下一个本字符之间的任一位置。

    假设 $i$ 的反操作可达区间为 $[L_i, R_i]setminus{i}$, 再记 $i$ 经过至多 $k$ 次反操作可达区间为 $[L_i^{(k)}, R_i^{(k)}]$.

    那么 $[L_i^{(k+1)}, R_i^{(k+1)}]=igcup_{L_i^{(k)} le x le R_i^{(k)}}[L_x, R_x]$.

    考虑在 $k$ 步之内还有哪些点不能到达,于是答案被改写成 $sum_{i=0}^{n-1}sum_{k=0}^{n-1}(n-1+L_i^{(k)}-R_i^{(k)})$.

    由于 $L^{(k)}$ 和 $R^{(k)}$ 互相影响,直接对着它们优化已经比较困难了。

    这里的思路比较巧妙。我们考虑一下 $[L_i^{(k)}, R_i^{(k)}]=[l, r]$ 进行一轮迭代后的区间 $[L_i^{(k+1)}, R_i^{(k+1)}]=[l', r']$。我们发现:如果假设 $p_1, p_2, ldots, p_t$ 是该区间内所有字符的最左出现位置,那么得出 $l'=min_{1 le j le t}L_{p_j}$. 进一步地,我们假设 $[l, r]$ 内一共有 $t$ 种字符,而 $l$ 以后字符的最左出现位置从左到右依次为 $p_1<p_2<cdots<p_{26}$(如果不存在设为 $n-1$),那么仍然有 $l'=min_{1 le j le t}L_{p_j}$. 因此我们可以设 $f_t(i)=min_{1 le j le t}L_{p_j}$, $g_t(i)$ 对应右端点的类似量。当 $t$ 不变时,$L_i^{(k)}$ 和 $R_i^{(k)}$ 独立。因此我们枚举 $t$, 对于每个 $i$ 求出最大的区间 $[L_i^{(k)}, R_i^{(k)}]$ 使得其中字符种数为 $t$. 用倍增求出 $f_t, g_t$ 各自迭代 $2^x$ 轮的结果以及迭代过程中的函数值之和,每次以 $t$ 不变为迭代限度进行倍增迭代即可求出答案。

    具体实现上,判断区间内种类数是否为 $t$ 可以借助前述的位置序列 ${p_j}$.

    实现

    #include <bits/stdc++.h>
    #define meow(args...) fprintf(stderr, args)
    template<class T1, class T2> inline bool cmin(T1 &a, const T2 &b) {return b<a?(a=b, true):false;}
    template<class T1, class T2> inline bool cmax(T1 &a, const T2 &b) {return a<b?(a=b, true):false;}
    
    const int N=1e5+5;
    int n, last[26], l[N], r[N], pre[N][27], nex[N][27], f[N][27], g[N][27], curl[N], curr[N], flift[17][N], glift[17][N];
    char s[N];
    long long fsum[17][N], gsum[17][N];
    int main() {
        assert(scanf("%s", s)==1);
        n=strlen(s);
        for(int i=0; i<n; ++i) s[i]-='a';
        for(int i=0; i<n; ++i) {
            l[i]=last[s[i]];
            last[s[i]]=i;
            memcpy(pre[i], last, sizeof(last));
            std::sort(pre[i], pre[i]+26, std::greater<int>());
            pre[i][26]=-1;
        }
        for(int i=0; i<26; ++i) last[i]=n-1;
        for(int i=n; i--; ) {
            r[i]=last[s[i]];
            last[s[i]]=i;
            memcpy(nex[i], last, sizeof(last));
            std::sort(nex[i], nex[i]+26);
            nex[i][26]=n;
        }
        for(int i=0; i<n; ++i) {
            curl[i]=curr[i]=i;
            f[i][0]=g[i][0]=i;
            for(int j=0; j<26; ++j) {
                f[i][j+1]=std::min(f[i][j], l[nex[i][j]]);
                g[i][j+1]=std::max(g[i][j], r[pre[i][j]]);
            }
        }
        long long ans=0;
        for(int t=1; t<=26; ++t) {
            for(int i=0; i<n; ++i) {
                flift[0][i]=f[i][t];
                glift[0][i]=g[i][t];
                fsum[0][i]=gsum[0][i]=i;
            }
            for(int i=1; (1<<i)<=n; ++i)
                for(int j=0; j<n; ++j) {
                    flift[i][j]=flift[i-1][flift[i-1][j]];
                    glift[i][j]=glift[i-1][glift[i-1][j]];
                    fsum[i][j]=fsum[i-1][j]+fsum[i-1][flift[i-1][j]];
                    gsum[i][j]=gsum[i-1][j]+gsum[i-1][glift[i-1][j]];
                }
            for(int i=0; i<n; ++i) {
                for(int j=31-__builtin_clz(n); j>=0; --j) {
                    int nexl=flift[j][curl[i]], nexr=glift[j][curr[i]];
                    if(nexr<nex[nexl][t]) {
                        ans+=((n-1ll)<<j)+fsum[j][curl[i]]-gsum[j][curr[i]];
                        curl[i]=nexl, curr[i]=nexr;
                    }
                }
                if(curr[i]<nex[curl[i]][t]) {
                    ans+=n-1+curl[i]-curr[i];
                    curl[i]=f[curl[i]][t];
                    curr[i]=g[curr[i]][t];
                }
            }
        }
        printf("%lld
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    明就要发布一加8pro了,发几张关于7的图片供大家回忆下
    【移动端开发】移动端开发项目架构
    【前端开发】three.js入门
    【前端依赖】live-server静态文件本热更新静态服务安装及使用教程
    【vue开发】泛型总结
    【vue前端开发】微信扫码登录
    【正则表达式】梳理
    【mock数据服务】大项目中mock的使用方法和注意事项
    【vue开发】v-bind="$attrs" v-on="$listeners" 多层组件监听
    【vue开发】render的用法,全局引入/组件简化代码
  • 原文地址:https://www.cnblogs.com/nealchen/p/CF1246F.html
Copyright © 2011-2022 走看看