hdu - 4346 - beautiful road - 枚举+想法

题意:

         给出一个字符串,字符串由"R","G","?"组成,若字符串存在2R,且2R中间是一个G,则称该串为“漂亮串”,现考虑将"?"

换成"R""G"的所有字符串,求这些字符串中“漂亮串”的总数。

我们从反面考虑问题,若字符串不是“漂亮串”,则字符串的形式必然为:R...R...R...R,相邻2R的距离相等且距离为奇

数。

       所以我们可以枚举距离,构造“非漂亮串”,毛估总共需要枚举的次数为n*n*(1/1+1/2+...1/n),时间复杂度为O(n^2logn),然后

用总的字符串数(2^k,k"?"总数)减去“非漂亮串”的总数,就是“漂亮串”的总数了。 

 

解释:

    就是我们把任意一个字符串s中的R全部提取出来(只考虑R),如果s不是beautiful string的话,那么所有的R一定具有解题思路里面那种形式

否则的话,就一定是beautiful string了,这个可以用反证法证明

 

反证分两步,证明相邻两个R距离不等以及存在距离为偶数

这个证明还是容易的

 

这样对每一个给定字符串,我们根据R的个数分别枚举距离就行了

/*
Pro: 0

Sol:

date:
*/
#include<cstdio>
#include<cstring>
using namespace std;
#define mod 1000000007
int t;
long long mod_pow(int a,int n,int p)
{
    long long ret=1;
    long long A=a;
    while(n){
        if (n & 1)
            ret=(ret*A)%p;
        A=(A*A)%p;
        n>>=1;
    }
    return ret;
}
int main(){
    scanf("%d",&t);
    while( t -- ){
        char str[808];
        scanf("%s",str);
        int len = strlen(str);
        int unknown = 0, r_num = 0;
        for(int i = 0; i < len; i ++){
            if(str[i] == '?') unknown ++;
            else if(str[i] == 'R') r_num ++;
        }
        long long unbea = (r_num == 0);//全为G的是不beautiful的。
        
        for(int i = 0; i < len; i ++){//开始遍历
            if(str[i] == 'R' || str[i] == '?'){//可能是R的情况
                int x = (str[i] == 'R');
                unbea = (unbea + (x == r_num) ) % mod;//这是给出的串只有一个R的情况
                
                for(int dis = 1; dis + i < len; dis += 2){// + i 枚举距离
                    int y = x;
                    for(int sta = i + dis; sta < len; sta += dis){//枚举第二个位置以及以后
                        y += (str[sta] == 'R');
                        if(str[sta] == 'G') break;
                        unbea = (unbea + (y == r_num) )% mod;//如果遍历到的点和R的个数相同
                        //那么,就加上一个不美丽字符串
                        //这一句话包含了(拿样例4做解释)
                        //RRRR
                        //RRRG RRGG
                        //RGGR
                        //GRRR GRRG
                        //GGRR
                    }
                }
            }
        }
        printf("%I64d\n",mod_pow(2,unknown,mod) - unbea);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值