CodeForces 696C PLEASE

快速幂,费马小定理,逆元。

设$dp[n]$表示$n$次操作之后的概率,那么$dp[n] = \frac{{(1 - dp[n - 1])}}{2}$。$1-dp[n - 1]$表示上一次没有在中间的概率,除以$2$表示$n$次操作之后的情况数是$n-1$次操作之后的两倍,所以要除以$2$,这个画画图就可以知道了。

也就是说,现在我们知道了$ - 2×dp[n] = dp[n - 1] - 1$

我们假设$ - 2*(dp[n] + X) = dp[n - 1] + X$,利用待定系数法,可以求得$X =  - \frac{1}{3}$。

那么,$\frac{{dp[n] - \frac{1}{3}}}{{dp[n - 1] - \frac{1}{3}}} =  - \frac{1}{2}$。 因此,$dp[n] - \frac{1}{3}$是首项为$ - \frac{1}{3}$,公比为$ - \frac{1}{2}$的等比数列。

可以计算得到:$dp[n] = \frac{{{{( - 1)}^n} + {2^{n - 1}}}}{{3×{2^{n - 1}}}}$。

通过观察可以发现,${{{( - 1)}^n} + {2^{n - 1}}}$与${{2^{n - 1}}}$之间必然是互质的,那么分子与分母之间的公约数要么是$3$,要么没有公约数。

所以,如果分子能被$3$整除,那么分子分母同除以$3$,即分子和分母再$×3$的逆元。

求解${{2^{n - 1}}}$可以通过费马小定理:${a^x}\% p = {a^{x\% \phi (p) + \phi (p)}}\% p$。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-8;
void File()
{
    freopen("D:\\in.txt","r",stdin);
    freopen("D:\\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
    char c = getchar(); x = 0;while(!isdigit(c)) c = getchar();
    while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar();  }
}

const int maxn=100010;
int k;
LL mod=1e9+7,pmod=1e9+6;
LL n,a[maxn];

LL extend_gcd(LL a,LL b,LL &x,LL &y)
{
    if(a==0&&b==0) return -1;
    if(b==0){x=1;y=0;return a;}
    LL d=extend_gcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}

LL mod_reverse(LL a,LL n)
{
    LL x,y;
    LL d=extend_gcd(a,n,x,y);
    if(d==1) return (x%n+n)%n;
    else return -1;
}

LL POW(LL a,LL b,LL m)
{
    LL d,t;
    d=1; t=a;
    while (b>0)
    {
        if (b%2==1) d=(d*t)%m;
        b/=2; t=(t*t)%m;
    }
    return d;
}

int main()
{
    scanf("%d",&k);
    for(int i=1;i<=k;i++) scanf("%lld",&a[i]);
    LL f=1,z=1;
    for(int i=1;i<=k;i++)
    {
        f=f*(a[i]%2)%2, z=z*(a[i]%pmod)%pmod;
    }
    z=(z-1+pmod)%pmod+pmod; if(f%2==0) f=1; else f=-1;
    LL fz=POW(2,z,mod); fz=(fz+f+mod)%mod;
    LL fm=POW(2,z,mod);

    z=1; for(int i=1;i<=k;i++) z=z*(a[i]%2)%2;
    z=(z-1+2)%2+2;
    LL t=POW(2,z,3); t=(t+f+3)%3;
    if(t==0) fz=fz*mod_reverse(3,mod)%mod;
    else fm=3*fm%mod;

    printf("%lld/%lld\n",fz,fm);
    return 0;
}

 

posted @ 2016-08-23 17:32  Fighting_Heart  阅读(245)  评论(0编辑  收藏  举报