吉首大学校赛 A SARS病毒 (欧拉降幂)

题目描述

目前,SARS 病毒的研究在世界范围内进行,经科学家研究发现,该病毒及其变种的 DNA 的一条单链中,胞嘧啶、腺嘧啶均是成对出现的。这虽然是一个重大发现,但还不是该病毒的最主要特征,因为这个特征实在太弱了。

为了进一步搞清楚该病毒的特征,CN 疾病控制中心和阿里巴巴集团合作,用科技的力量和程序的思维来解决这个难题。现阿里巴巴特委派你成为 CN 疾病控制中心的 SARS 高级研究员,去研究在这个特征下,可能成为 SARS 病毒的 DNA 序列的个数。更精确地说,你需要统计所有满足下列条件的长度为 n 的字符串的个数:

  1. 字符串仅由 A、T、C、G 组成
  2. A 出现偶数次(也可以不出现)
  3. C 出现偶数次(也可以不出现)

当 n=2 时,所有满足条件的字符串有如下 6个:

TT,TG,GT,GG,AA,CC。

注: 由于这个数可能非常庞大,你只需给出对 10^9+7 取模的结果即可。

输入描述:

多组输入(不超过10组),每行一个整数n:0 < n < 1010510105

输出描述:

对于输入文件中的每一个 n,输出满足条件的字符串的个数对 10^9 +7 取模的结果。
示例1

输入

复制
1
2
100

输出

复制
2
6
113046907


题意:满足题目的序列个数有多少个
思路:我们计算以每个字母结尾的个数有多少个,我们可以分两类((T,G),(A,C)),T,G字母结尾的我们每一位都会翻两倍,A,C字母每隔俩个翻一倍,但是其实我们A,C结尾的我们可以放T,G,T,G结尾也一样,所以
假设 AC[]代表 AC结尾 TG[]代表 TG结尾
AC[n] = AC[n-2]*2 + TG[n-2]*2;
TG[n] =  AC[n-1]*2 +  TG[n-1]*2;
最后我们可以化简出式子等于 (2^(n-1))*(2^(n-1)+1)
因为我们的n特别大,这里我就用上了欧拉降幂
(a^n)%mod = (a^(b%phi(mod)+mod))%mod

ps:猜结论的话,排列组合需要往指数方向去靠

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<stack>
#include<cstdlib>
#include<queue>
#include<set>
#include<string.h>
#include<vector>
#include<deque>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define eps 1e-4
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
typedef long long LL;
typedef long long ll;
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;

// 求解 x ^ a mod z ,其中 a 是一个大整数,欧拉降幂
char a[1000006];
ll x,z;
ll quickpow(ll x,ll y,ll z) {
    ll ans = 1;
    while (y) {
        if (y & 1)
            ans = ans * x % z;
        x = x * x % z;
        y >>= 1;
    }
    return ans;
}
ll phi(ll n) {
    ll i, rea = n;
    for (i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            rea = rea - rea / i;
            while (n % i == 0)
                n /= i;
        }
    }
    if (n > 1)
        rea = rea - rea / n;
    return rea;
}
int main() {
    while (scanf("%s", a) != EOF) {
        ll len = strlen(a);
        z = mod;
        ll p = phi(z);
        ll ans = 0;
        for (ll i = 0; i < len; i++)
            ans = (ans * 10 + a[i] - '0') % p;
        ans += p;
        printf("%lld\n", (quickpow(2, ans - 1, z) + quickpow(4, ans - 1, z)) % mod);
    }
    return 0;
}
View Code

 

posted @ 2019-08-29 16:45  千摆渡Qbd  阅读(224)  评论(0)    收藏  举报