题意:
一个字符串“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;
}