Educational Codeforces Round 153 D-E dp,bfs

1860D Balanced String
首先只能是0和1交换,1在 i i i位置,0在 j j j位置,每交换一次产生的贡献是 2 ∗ ( i − j ) 2*(i-j) 2(ij),所以我们可以先算出原01串中所需要的贡献 m m m,我们发现找到 t o l tol tol 个1和0的位置 i k , j k i_k,j_k ik,jk ∑ k t o l i k − j k = m \sum_{k}^{tol} i_k-j_k=m ktolikjk=m,我们可以拆开 ∑ k t o l i k − ∑ k t o l j k = m \sum_{k}^{tol} i_k- \sum_{k}^{tol} j_k=m ktolikktoljk=m,然后分别dp出选tol个数,0,1的位置和分别有那些状态可以达到,易证位置和小于 n 2 n^2 n2,然后枚举 t o l tol tol,枚举1的位置和,算出0的位置和,判断两个状态是否能达到
时间复杂度 O ( n 4 ) O(n^4) O(n4)

void solve(){
    std::string s;
    std::cin>>s;
    int n=s.length();

    std::vector<int> a(n+1);
    int sum=0,m=0;
    for (int i=1;i<=n;i++){
        a[i]=s[i-1]-'0';
        if (a[i]){
            m-=i-1-sum;
        }else{
            m+=sum;
        }
        sum+=a[i];
    }

    m>>=1;
    std::vector<std::vector<int>> dp0(n+1,std::vector<int>(n*n+1)),dp1(n+1,std::vector<int>(n*n+1));
    dp0[0][0]=dp1[0][0]=1;
    for (int i=1;i<=n;i++){
        for (int j=i;j>=1;j--){
            for (int k=n*n;k>=i;k--){
                if (a[i]){
                    dp1[j][k]|=dp1[j-1][k-i];
                }else{
                    dp0[j][k]|=dp0[j-1][k-i];
                }
            }
        }
    }
    m=-m;
    for (int i=0;i<=n;i++){
        for (int j=0;j<=n*n;j++){
            int k=j-m;
            if (k>=0&&k<=n*n&&dp1[i][j]&&dp0[i][k]){
                std::cout<<i;
                return;
            }
        }
    }
}

1860E Fast Travel Text Editor
首先注意到是小写字母,说明最多 26 * 26 种组合方式,然后发现题意每次操作代价都为1,考虑建图,发现连边和对点的定义不好搞,考虑bfs,定义 d i s i , j , x dis_{i,j,x} disi,j,x,表示当前点 x x x,到某个形如 ′ a ′ + i , ′ a ′ + j 'a'+i,'a'+j a+i,a+j位置的最小距离,这样我们每次询问只要枚举 26 * 26 次,类似Floyed找中转点的方法, m i n ( y − x , d i s i , j , x + d i s i , j , y + 1 ) min(y-x,dis_{i,j,x}+dis_{i,j,y}+1) min(yx,disi,j,x+disi,j,y+1)

我们枚举每个 i , j i,j i,j,然后从形如 ′ a ′ + i , ′ a ′ + j 'a'+i,'a'+j a+i,a+j的位置出发,bfs向外扩展,更新各点的 d i s i , j , x dis_{i,j,x} disi,j,x,每次扩展除了到 x + 1 x+1 x+1 x − 1 x-1 x1点外,还要让 x x x通过第三种操作跳跃到其它点,由于每个点最多入队一次,所以时间复杂度为 O ( 2 6 2 ∣ s ∣ ) O(26^2\vert s \vert) O(262s)
总时间复杂度 O ( 2 6 2 ( m + ∣ s ∣ ) ) O(26^2 (m+\vert s \vert)) O(262(m+s))

const int inf=1e9;
void solve(){
    std::string s;
    std::cin>>s;
    int n=s.length();
    std::vector<int> pos[26][26];
    for (int i=1;i<n;i++){
        pos[s[i-1]-'a'][s[i]-'a'].push_back(i);
    }

    std::vector dis(26,std::vector(26,std::vector(n+2,inf)));
    for (int i=0;i<26;i++){
        for (int j=0;j<26;j++){
            std::queue<int> q;
            for (auto x:pos[i][j]){
                q.push(x);
                dis[i][j][x]=0;
            }
            std::vector<std::vector<int>> vis(26,std::vector<int>(26));
            vis[i][j]=1;

            while (!q.empty()){
                int x=q.front();
                q.pop();

                if (x-1>=1&&dis[i][j][x-1]==inf){
                    dis[i][j][x-1]=dis[i][j][x]+1;
                    q.push(x-1);
                }
                if (x+1<n&&dis[i][j][x+1]==inf){
                    dis[i][j][x+1]=dis[i][j][x]+1;
                    q.push(x+1);
                }
                int l=s[x-1]-'a',r=s[x]-'a';
                if (!vis[l][r]){
                    vis[l][r]=1;
                    for (auto v:pos[l][r]){
                        if (dis[i][j][v]==inf){
                            dis[i][j][v]=dis[i][j][x]+1;
                            q.push(v);
                        }
                    }
                }
            }
        }
    }

    int m;
    std::cin>>m;
    while (m--){
        int x,y;
        std::cin>>x>>y;
        int ans=abs(x-y);
        for (int i=0;i<26;i++){
            for (int j=0;j<26;j++){
                ans=std::min(ans,dis[i][j][x]+dis[i][j][y]+1);
            }
        }
        std::cout<<ans<<"\n";
    }
    
}

你可能感兴趣的:(codeforces,算法)