zoukankan      html  css  js  c++  java
  • codeforces gym 100345I Segment Transformations [想法题]

    题意简述

    给定一个由A C G T四个字母组成的密码锁(每拨动一次 A变C C变G G变T T变A)

    密码锁有n位 规定每次操作可以选取连续的一段拨动1~3次

    问最少几次操作可以将初始状态变到末状态

    并且把每次操作输出

    (此题有spj)

    ---------------------------------------------------------------------------------------------------------

    为了方便叙述 所有没有明确说明的位置均是在$mod4$意义下的

    首先我们显然可以明白一个性质 操作顺序是没关系的

    有关系的只是每个位置被拨动的次数

    比赛的时候一开始想的是比较随意的贪心 然而是有反例的

    最后剩下30min的时候 从数据范围想到了区间Dp

    然而这题并不是一般的区间Dp

    最小操作数好求然而操作方案难以记录

    补题的时候 最终又去想象有没有什么更好的贪心思路

    ---------------------------------------------------------------------------------------------------------

    我们用一个高度数组h记录从初始状态到末状态每个位置需要拨动的次数

    比如样例

    AGGTCAT

    AAACTAA

    高度数组h便是 0222201

    我们再定义一个delta数组 代表所有的$h[i]-h[i-1]$

    那么从$1$到$n+1$delta数组的值便是 02000213

    (这样的构造类似与用树状数组维护区间加减值的做法 不过这种思想的具体名称我也不知道)

    显然我们每次最优可以将两个2变为0 或者将一个1和一个3变为0

    于是这样就可以做了?

    然而只是这样做的话会RE11

    ---------------------------------------------------------------------------------------------------------

    比如这样一个样例

    AA

    GT

    高度数组h为 23

    delta数组为 211

    于是并不能找出两个2或者一个1一个3来配对消除

    既然无法一次消两个 我们就一次消一个吧

    不过显然是不能使一些已经消除的部分又出现

    所以直接找两个非0的进行处理 把其中一个变为0就好了

    (注意到delta数组之和为0 所以最后一定不会只剩下一个非0的)

    #include <bits/stdc++.h>
    using namespace std;
    const int N=110;
    char s1[N],s2[N];
    int h[N],delta[N],cnt[4];
    int L[N],R[N],d[N];
    int n,ans;
    int main()
    {
    #ifdef ONLINE_JUDGE
            freopen("transform.in","r",stdin);
            freopen("transform.out","w",stdout);
    #endif
            scanf("%s%s",&s1[1],&s2[1]);
            n=strlen(&s1[1]);
            for(int i=1;i<=n;++i)
            {
                if(s1[i]=='A')
                    h[i]=-0;
                else if(s1[i]=='C')
                    h[i]=-1;
                else if(s1[i]=='G')
                    h[i]=-2;
                else
                    h[i]=-3;
                if(s2[i]=='A')
                    h[i]+=0;
                else if(s2[i]=='C')
                    h[i]+=1;
                else if(s2[i]=='G')
                    h[i]+=2;
                else
                    h[i]+=3;
                h[i]=h[i]<0?h[i]+4:h[i];
            }
            for(int i=1;i<=n+1;++i)
            {
                delta[i]=(h[i]-h[i-1]+4)%4;
                cnt[delta[i]]++;
            }
            while(cnt[0]!=n+1)
            {
                ++ans;
                int i=1;
                while(!delta[i])
                    ++i;
                int j=i+1;
                while(delta[j]+delta[i]!=4&&j<=n+1)
                    ++j;
                if(j<=n+1)
                {
                    L[ans]=i;
                    R[ans]=j-1;
                    d[ans]=delta[i];
                    cnt[delta[i]]--;
                    cnt[delta[j]]--;
                    cnt[0]+=2;
                    delta[i]=delta[j]=0;
                }
                else
                {
                    j=i+1;
                    while(!delta[j])
                        ++j;
                    L[ans]=i;
                    R[ans]=j-1;
                    d[ans]=delta[i];
                    cnt[delta[i]]--;
                    cnt[delta[j]]--;
                    cnt[0]++;
                    cnt[(delta[j]+delta[i])%4]++;
                    delta[j]=(delta[j]+delta[i])%4;
                    delta[i]=0;
                }
            }
            printf("%d
    ",ans);
            for(int i=1;i<=ans;++i)
                printf("%d %d %d
    ",L[i],R[i],d[i]);
        return 0;
    }
  • 相关阅读:
    JS站点
    1011 World Cup Betting (20分)
    1007 Maximum Subsequence Sum (25分)(动态规划DP)
    1006 Sign In and Sign Out (25分)
    1005 Spell It Right (20分)
    1004 Counting Leaves (30分)(DFS)
    1003 Emergency (25分)(Dijkstra算法)
    1002 A+B for Polynomials (25分)
    1001 A+B Format (20分)
    canvas
  • 原文地址:https://www.cnblogs.com/sagitta/p/4770389.html
Copyright © 2011-2022 走看看