HDU 4662 MU Puzzle

比赛

题目

题意:

一个字符串“MI”,每次可以将M后面的所有字符串翻倍,或者将连续的3个I变成一个U,或者消掉2个连续的U,问能否变到目标串。

题解:

可以把U换算成3个I,那么目标串中I的个数有cnt个。而任何地方原来可能有两个U,也就是6个I,设消掉了6x个,那么昨晚翻倍操作后有cnt+6x个I。由于翻倍是每次乘2,所以求是否有x使得6x+cnt为2的幂。

将cnt%6,则cnt-cnt%6可以归入x部分,求出第一个大于cnt-cnt%6的2的幂,则可知要刚好为2的幂还差多少,若不等于cnt%6则翻倍。如果循环则无解。

注意目标串可能有多个M、第一个字符不是M、M后面没有字符等情况,都是No。

//Time:
//Memory:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 1000010
#define INF 1000000007
char str[MAXN];
bool vi[10];
int main()
{
    //freopen("/home/moor/Code/input","r",stdin);
    int ncase;
    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%s",str);
        memset(vi,0,sizeof(vi));
        int cnt=0;
        bool flag=1;
        for(int i=1;str[i];++i)
            if(str[i]=='I') ++cnt;
            else    if(str[i]=='M') flag=0;
            else    if(str[i]=='U') cnt+=3;
        if(cnt==0)  flag=0;
        if(str[0]!='M') flag=0;
        if(flag)
        {
            if(cnt>1)
            {
                int a=cnt%6,lef=1;
                while(lef<cnt-a)
                    lef<<=1;
                lef%=6;
                while(flag)
                {
                    if(lef==a)    break;
                    if(vi[lef]==1)
                    {
                        flag=0;
                        break;
                    }
                    vi[lef]=1;
                    lef=lef*2%6;
                }
            }
        }
        printf("%s\n",flag?"Yes":"No");
    }
    return 0;
}


你可能感兴趣的:(HDU 4662 MU Puzzle)