2065 hdu 红色病毒【快速幂】

本文深入探讨了一种递推算法的设计思路,通过分析四个字符组成的字符串中特定条件下的组合数量问题,详细介绍了如何利用递推思想解决该问题,并最终简化得出简洁的公式。

问题分析
Problem Analyse 递推题

Algorithm Analyse 比起以前做过的递推题,这一题算比较麻烦的了(当然,原因是我没有想到

好的方法,如果你有更方便的方法,欢迎提供大家一起学习)。
如果没有任何条件限制,A、B、C、D组成长度为n的字符串,其个数应该为:4n。

因为有了A、C需要出现偶数次的要求,就出现合法和不合法的不同分组。
在不合法的组里,又有
1.A出现奇数次、C出现偶数次;
2.C出现奇数次、A出现偶数次;
3.A出现奇数次、C出现奇数次;
三种情况。

我们用数组
f[n][0]保存长度为n,合法的字符串的个数。
f[n][1]保存长度为n,仅A出现奇数次的字符串的个数。
f[n][2]保存长度为n,仅C出现奇数次的字符串的个数。
f[n][3]保存长度为n,A、C出现奇数次的字符串的个数。

f[n][0]
长度为n-1的合法字符串在末尾加上一个B或者D,都可以变成长度为n的合法字符串。
长度为n-1的仅A出现奇数次的字符串再在末尾加上一个A,也可以变成合法字符串。
长度为n-1的仅C出现奇数次的字符串再在末尾加上一个C,也可以变成合法字符串。
所以,f[n][0] = 2 × f[n-1][0] + f[n-1][1] + f[n-1][2];

f[n][1]
长度为n-1的合法字符串在末尾加上A,都可以变成长度为n的仅A出现奇数次的字符串。
长度为n-1的仅A出现奇数次的字符串再在末尾加上一个B或者D,也可以变成仅A出现奇数次的字

符串。
长度为n-1的A、C出现奇数次的字符串再在末尾加上一个C,也可以变成仅A出现奇数次的字符串


所以,f[n][1] = 2 × f[n-1][1] + f[n-1][0] + f[n-1][3];

f[n][2]
长度为n-1的合法字符串在末尾加上C,都可以变成长度为n的仅C出现奇数次的字符串。
长度为n-1的仅C出现奇数次的字符串再在末尾加上一个B或者D,也可以变成仅C出现奇数次的字

符串。
长度为n-1的A、C出现奇数次的字符串再在末尾加上一个A,也可以变成仅C出现奇数次的字符串


所以,f[n][2] = 2 × f[n-1][2] + f[n-1][0] + f[n-1][3];

f[n][3]
长度为n-1的A、C出现奇数次的字符串在末尾加上一B或者D,都可以变成长度为n的A、C出现奇数

次的字符串。
长度为n-1的仅A出现奇数次的字符串再在末尾加上一个C,也可以变成A、C出现奇数次的字符串


长度为n-1的仅C出现奇数次的字符串再在末尾加上一个A,也可以变成A、C出现奇数次的字符串


所以,f[n][3] = 2 × f[n-1][3] + f[n-1][1] + f[n-1][2];

综上所述,我们得到:
f[n][0] = 2 × f[n-1][0] + f[n-1][1] + f[n-1][2]; ①
f[n][1] = 2 × f[n-1][1] + f[n-1][0] + f[n-1][3]; ②
f[n][2] = 2 × f[n-1][2] + f[n-1][0] + f[n-1][3]; ③
f[n][3] = 2 × f[n-1][3] + f[n-1][1] + f[n-1][2]; ④

f[1][0] = 2
f[1][1] = 1
f[1][2] = 1
f[1][3] = 0

/**** 搞出这个我就很哈皮的去敲快速幂了。。。然而大牛。。。 ****/

发现f[1][1]与f[1][2]初始状态相同,而且以后迭代方程也相同,所以f[n][1] = f[n][2]
又有f[n][0] + f[n][3] = f[n][1] + f[n][2]
∵f[n][0] + f[n][1] + f[n][2] + f[n][3] = 4^n
∴f[n][0] + f[n][3] = f[n][1] + f[n][2] = 2 × 4^(n-1)
∴f[n-1][1] + f[n-1][2] = 2 × 4^(n-2)
∴f[n][0] = 2 × f[n-1][0] + f[n-1][1] + f[n-1][2] = 2 × f[n-1][0] + 2 × 4^(n-2)

我们得到:
f[n][0] = 2 × f[n-1][0] + 2^(2n-3)
f[n-1][0] = 2 × f[n-2][0] + 2^(2n-5)

f[n-m][0] = 2 × f[n-m-1][0] + 2^(2n-2m-3)

f[2][0] = 2 × f[1][0] + 2^1
f[1][0] = 2

开始一层层往下迭代:
f[n][0]
= 2 × f[n-1][0] + 2^(2n-3)
= 2^2 × f[n-2][0] + 2^(2n-4) + 2^(2n-3)

= 2^m × f[n-m][0] + 2^(2(n-m)-1+m-1) + … + 2^(2n-3)
= 2^(n-1) × f[1][0] + 2^(n-1) + 2^n +… + 2^(2n-3)
f[1][0] = 2;

∴f[n][0] = 2^n + 2^(n-1) + 2^n +… + 2^(2n-3) = 2^(2n-2) + 2^(n-1)


  1.     #include<stdio.h>  
        int Pow(__int64 n)  
        {  
            int r= 1,b= 2;  
            while(n!=0)  
            {  
                if(n%2)  
                    r=(r* b)% 100;  
                b= (b* b)% 100;  
                n/= 2;    
            }  
        return r;   
        }  
        int main()  
        {  
            int n;  
            while(scanf("%d",&n)!=EOF&&n)  
            {  
                __int64 a;  
                int t= 0;  
                while(n--)  
                {  
                    scanf("%I64d",&a);  
                    t++;  
                    int ans;  
                    ans= (Pow(a-1) + Pow(2*a -2))% 100;  
                    printf("Case %d: %d\n",t,ans);  
                }  
                printf("\n");  
            }  
            return 0;  
        }  

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值