题意:给定三个表达式,问你求出最小的m1,m2,满足G(m1) >= F(n), G(m2) >= G(n).
析:这个题是一个概率DP,但是并没有那么简单,运算过程很麻烦。
先分析F(n),这个用DP来推公式,d[i],表示抛 i 次连续的点数还要抛多少次才能完成。那么状态转移方程就是 d[i] = 1/6*(1+d[i+1]) + 5/6*(1+d[1]),
意思就是说在第 i 次抛和上次相同的概率是1/6,然后加上上次抛的和这一次,再加上和上次不同的,并且又得从第1次开始计算。
边界就是d[0] = 1/6*(1+d[1]) + 5/6*(1+d[1]), d[n] = 0;然后去解出d[1]来,然后把d[0]解出来,结果就是F(n) = (6^n-1)/5;
然后再去计算H(n) = 6 * F(n),当然也可以用DP来推,d[i]表示抛 i 次连续的1还要抛多少次才能完成,方程为d[i] = 1/6*(1+d[i+1]) + 5/6*(1+d[0]),
意思和上面差不多,就是改了一个d[0],因为是连续的1,如果不是1,就得从0开始。同样把d[0]解出来,即可。
G(n) = 6 * n;那就可以解出来m1, m2,m1 >= (6^n-1)/30, m2>=(6^n-1)/5,
很明显可以知道m1 = (6^n-1)/30, m2 = (6^n+24)/5,然后就能算出来,由于 n 比较大,还有除法,所以可以先把5,30的逆元先求出来,然后再进行计算。
5的逆元在这个题上是1609,30的逆元在这个题上是1944.然后用快速幂就可以求出来。
代码如下:
#include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <set> #include <queue> #include <algorithm> #include <vector> #include <map> #include <cctype> using namespace std ; typedef long long LL; typedef pair<int, int> P; const int INF = 0x3f3f3f3f; const double inf = 0x3f3f3f3f3f3f3f; const double eps = 1e-8; const int maxn = 56 + 5; const int mod = 2011; const int e5 = 1609; const int e30 = 1944; const int dr[] = {0, 0, -1, 1}; const int dc[] = {-1, 1, 0, 0}; int n, m; inline bool is_in(int r, int c){ return r >= 0 && r < n && c >= 0 && c < m; } LL quick_pow(LL a, LL b){ LL k = a % mod; LL ans = 1; while(b){ if(b & 1) ans = (k * ans) % mod; b >>= 1; k = k * k % mod; } return ans; } int main(){ LL n; while(cin >> n, n){ LL a = quick_pow(6, n); LL ans1 = (a+24) * e30 % mod; LL ans2 = (a-1) * e5 % mod; cout << ans1 << " " << ans2 << endl; } return 0; }