中文题意

给出个数,你需要操作的次数是,现在你有3个盘子,假设编号是0,1,2,初始我们编号1中有一个小球,每次操作可以在0,2中选择一个盘子和1做一次交换,并且重新做编号。问做次操作之后,小球还留在1号盘子的概率是多少,输出最简分数的形式。

Solution

我们首先使用动态规划进行递推最终答案,我们假设代表第步留在0,1,2号盘子的概率。那么我们得到转移方程是。
对于每个位置都可能从旁边转移过来以及之前就保留在这个位置,并且这次选择要选择正确的移动。
那么观察我们不难发现0号和2号盘子是对称的。所以我们可以得到把它带入中。
再次化简你会得到:
再把看成带入中,你会得到:
同理再做一次代换可以得到:
那么我们就拿到了一个线性递推的求解的方程,但是这是一个二阶递推式,还需要做一次化简。
我们把式子写成。套用特征方程的求解办法,可以解得每一项的通解。这里给个比较好的学习地址把,如果还有不会求解二阶递推式的同学可以去这里学学传送门
特征方程是,求解到2个根分别是
再带入,求解到,解得
那么我们就解到一阶的通项公式,
当然化简到上面的式子你就几乎成功了,再看约分的事情,因为分子一定是一个奇数,所以分子分母之间一定没有因子2,所以2的幂次直接照算即可。但是我们再看3,枚举几项你会发现,当是奇数的时候,他们一累加一定是3的倍数,同理当是偶数的时候,他们一累加也变成3的倍数了,所以得出结论,分子分母一定可以把3约掉。
最后再处理幂次的时候,按照费马小定理就模上即可,注意幂次可能取模变成0了,这样如果你直接在后面快速幂求解就会出问题,小心这样的小陷阱。

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<int, int>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
#define rep(i, sta, en) for(int i=sta; i<=en; ++i)
#define repp(i, sta, en) for(int i=sta; i>=en; --i)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op)    putchar(op); return; }    char F[40]; ll tmp = x > 0 ? x : -x;    if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]);    if (op)    putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct Node {
    ll val;
    int id;
    bool operator < (const Node& opt) const {
        return val < opt.val;
    }
};

const int N = 1e6 + 7;
ll n, m;
ll p[N];
void solve() {
    n = read();
    ll mi = 1;
    rep(i, 1, n) {
        ll x = read();
        mi = x % (MOD - 1) * mi % (MOD - 1);
    }
    if (mi == 0)    mi = MOD - 1;
    ll up = qpow(2, mi - 1, MOD);
    if (mi & 1)    up = (up - 1 + MOD) % MOD;
    else up = (up + 1) % MOD;
    up = up * qpow(3, MOD - 2, MOD) % MOD;
    ll dw = qpow(2, mi - 1, MOD);
    printf("%lld/%lld\n", up, dw);
}

int main() {
    //int T = read();    while (T--)
    solve();
    return 0;
}