HDU2065 "红色病毒"问题 【组合数学 二项式定理】

HDU2065 "红色病毒"问题

🔗

Description:
医学界发现的新病毒因其蔓延速度和Internet上传播的"红色病毒"不相上下,被称为"红色病毒",经研究发现,该病毒及其变种的DNA的一条单链中,胞嘧啶,腺嘧啶均是成对出现的。
现在有一长度为N的字符串,满足一下条件:
(1) 字符串仅由A,B,C,D四个字母组成;
(2) A出现偶数次(也可以不出现);
(3) C出现偶数次(也可以不出现);
计算满足条件的字符串个数.
当N=2时,所有满足条件的字符串有如下6个:BB,BD,DB,DD,AA,CC.
由于这个数据肯能非常庞大,你只要给出最后两位数字即可.

Input:
每组输入的第一行是一个整数T,表示测试实例的个数,下面是T行数据,每行一个整数N(1<=N<2^64),当T=0时结束.

Output:
对于每个测试实例,输出字符串个数的最后两位,每组输出后跟一个空行.

Sample Input:
4
1
4
20
11
3
14
24
6
0

Sample Output:
Case 1: 2
Case 2: 72
Case 3: 32
Case 4: 0

Case 1: 56
Case 2: 72
Case 3: 56

题解:

可以发现\(AC\)等价,\(BD\)等价,现在要求计算方案数,A和C都是出现偶数次,我们首先枚举A和C一共出现的次数(一次出现指出现两个\(A\)或两个\(C\)),从\(0\)\(\frac{n}{2}\),假设现在\(AC\)一共出现\(i\)次(一共\(2i\)个),接下来我们首先计算\(BD\)的位置的方案数,显然此时方案数为\(C(n,n-2i)\cdot 2^{n-2i}\)(先选定位置,然后每个位置可以放\(B\)或者\(D\)),接下来考虑\(AC\)的分配,也即把剩下的\(2i\)个位置分配给\(AC\),那么可以枚举\(A\)的出现次数,从\(0\)\(2i\),且必然是偶数,根据以上,可以的到一个计数的表达式:
\(Ans = \sum_{i=0}^{\frac{n}{2}}[C(n,n-2i)\cdot 2^{n-2i}\cdot \sum^{i}_{j=0}C(2i,2j)]\)
可以发现里面的那个求和,其实就是计算组合数的偶数项,那么可以知道\(\sum_{j=0}^{i}C(2i,2j)=2^{2i-1}\),但是要注意\(i=0\)的情况下是不成立的,所以需要把\(i=0\)的项单独拿出来,式子就变成这样了:
\(Ans = 2^{n} + \sum_{i=1}^{\frac{n}{2}}[C(n,n-2i)\cdot 2^{n-2i}\cdot 2^{2i-1}]\)
\(=2^{n} + \sum_{i=1}^{\frac{n}{2}}[C(n,n-2i)\cdot 2^{n-1}]\)
\(=2^{n} + 2^{n-1}\cdot \sum_{i=1}^{\frac{n}{2}}[C(n,n-2i)]\)
\(=2^{n} + 2^{n-1}\cdot (\sum_{i=0}^{\frac{n}{2}}[C(n,n-2i)] - 1)\)
\(=2^{n} + 2^{n-1}\cdot (2^{n-1}-1)\)
\(=2^{n-1}\cdot (2^{n-1}+1)\)

//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
int qpow(long long p){
    int ret = 1, base = 2;
    while(p){
        if(p&1) ret = ret * base % 100;
        p >>= 1;
        base = base * base % 100;
    }
    return ret;
}
void solve(int T){
    for(int kase = 1; kase <= T; kase++){
        int_fast64_t n; scanf("%I64d",&n);
        printf("Case %d: %d\n",kase,(qpow(n-1)*(qpow(n-1)+1))%100);
    }
    puts("");
}
int main(){
    int T; while(scanf("%d",&T) and T) solve(T);
    return 0;
}
posted @ 2020-03-28 18:23  _kiko  阅读(228)  评论(0编辑  收藏  举报