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\n",ans);
        for(int i=1;i<=ans;++i)
            printf("%d %d %d\n",L[i],R[i],d[i]);
    return 0;
}
时间: 2024-08-28 14:50:42

codeforces gym 100345I Segment Transformations [想法题]的相关文章

codeforces 657C - Bear and Contribution [想法题]

题目链接: http://codeforces.com/problemset/problem/657/C -------------------------------------------------------------------------------------------------------- 题目的特别之处在于只有 $+1$ $+5$ 这两种操作 我们要考虑如何利用这个条件 多想一下后可以发现 如果最优解的目标值为$x($将至少$k$个人的值增加到$x)$ 那么一定存在一个

Codeforces GYM 100114 B. Island 水题

B. Island Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Description On February 30th this year astronauts from the International Space Station flew over the Pacific Ocean and took a picture, on which was discovered a pr

Codeforces gym 100685 C. Cinderella 水题

C. CinderellaTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100685/problem/C Description Cinderella is given a task by her Stepmother before she is allowed to go to the Ball. There are N (1 ≤ N ≤ 1000) bottles with water in th

codeforces 584E Anton and Ira [想法题]

题意简述: 给定一个$1$到$n(n<=2000)$的初始排列以及最终排列 我们每次可以选取位置为$i$和$j$的 并交换它们的位置 花费为$ |i-j| $ 求从初始状态变换到末状态所需最小花费 ----------------------------------------------------------------------------------------------------------- 比赛时这题留了$40min$ 然而自己贪心策略还是有漏洞 结束后看了首页的官方题解 感

codeforces 397A On Segment&#39;s Own Points-yy

题意:有很多区间,找出目标区间不跟任何其他区间重叠的部分的长度 分析: 觉得很简单的题,但是脑子没转过弯了,一直没对. 思路就是用一个vis[]数组记录这个点是否被其他区间用了,但是不知道怎么了,我一直固执的要记录两个端点,结果,当然怎么都不对,因为要求的是区间的长度,跟点的个数不是一致的,而且最致命的就是这种方法会错过这样的区间:比如被别人占有的区间是(1,2),(3,4)  则目标区间还能用(2,3),但是如果记录了两个端点,那么会漏掉这个情况.然后我就一直卡在这了.其实只要记录区间的一个端

Codeforces Gym - 101147J Whistle&#39;s New Car

Discription Statements Whistle has bought a new car, which has an infinite fuel tank capacity. He discovered an irregular country since it has n cities and there are exactly n?-?1roads between them, of course, all cities are connected. He is so much

Codeforces Round #634 (Div. 3) 补题

A. Candies and Two Sisters 签到题,直接输出即可 代码 #include<bits/stdc++.h> #define INF 0x3f3f3f3f typedef long long ll; using namespace std; inline void read(int &p) { p=0;int flag=1;char c=getchar(); while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();} w

Codeforces gym Hello 2015 Div1 B and Div2 D

Codeforces gym 100571 problem D Problem 给一个有向图G<V,E>和源点S,边的属性有长度L和颜色C,即E=<L,C>.进行Q次询问,每次给定一个点X,输出S到X的最短路的长度(不存在则输出 -1).但要求S到X的路径中相邻两条边颜色不一样. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 |V|, |E|: [1, 10^5] X, S: [1, |V| ] L: [1, 10^9] |C|

Codeforces Round #257 (Div. 2) E题:Jzzhu and Apples 模拟

E. Jzzhu and Apples time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Jzzhu has picked n apples from his big apple tree. All the apples are numbered from 1 to n. Now he wants to sell them to