804 字
4 分钟
vijos 黑红树
2017-07-30

题目描述#

Mz们在czy的生日送他一个黑红树种子……czy种下种子,结果种子很快就长得飞快,它的枝干伸入空中看不见了……

Czy发现黑红树具有一些独特的性质。

  1. 这是二叉树,除根节点外每个节点都有红与黑之间的一种颜色。

  2. 每个节点的两个儿子节点都被染成恰好一个红色一个黑色。

  3. 这棵树你是望不到头的(树的深度可以到无限大)

  1. 黑红树上的高度这样定义(根节点)=0,h[son]=h[father]+1。

Czy想从树根顺着树往上爬。他有p/q的概率到达红色的儿子节点,有1-p/q的概率到达黑色节点。但是他知道如果自己经过的路径是不平衡的,他会马上摔下来。一条红黑树上的链是不平衡的,当且仅当红色节点与黑色节点的个数之差大于1。现在他想知道他刚好在高度为h的地方摔下来的概率的精确值a/b,gcd(a,b)=0。那可能很大,所以他只要知道a,b对K取模的结果就可以了。另外,czy对输入数据加密:第i个询问Qi真正大小将是给定的Q减上一个询问的第一个值a%K.

输入#

第一行四个数p,q,T,k,表示走红色节点概率是p/q,以下T组询问,答案对K取模。接下来T行,每行一个数 Q,表示czy想知道刚好在高度Q掉下来的概率(已加密)

输出#

输出T行,每行两个整数,表示要求的概率a/b中a%K和b%K的精确值。如果这个概率就是0或1,直接输出0 0或1 1(中间有空格)。

样例输入#

样例输入1

2 3 2 100
1
2

样例输入2

2 3 2 20
4
6

样例输出#

样例输出1

0 0
5 9

样例输出2

0 1 0 9

提示#

对于30%数据,p,q<=5,T<=1000,K<=127,对于任意解密后的Q,有Q<=30

对于60%数据,p,q<=20,T<=100000,K<=65535,对于任意解密后的Q,有Q<=1000

对于100%数据,p,q<=100,T<=1000000, K<=1000000007,对于任意解密后的Q,有Q<=1000000

对于100%数据,有q>p,即0<= p/q<=1

题解#

不写了
主要就是两行两行的考虑

#include <cstdio>
#include <cstring>
int P;
class frac
{
  public:
    long long a, b;
    long long gcd(long long A, long long B)
    {
        return B == 0 ? A : gcd(B, A % B);
    }
    frac Update(frac s)
    {
        if (s.a == 0)
            return s;
        int GCD = s.gcd(s.a, s.b);
        return (frac){s.a / GCD, s.b / GCD};
    }
    frac operator*(const frac A)
    {
        return (frac){a * A.a % P, b * A.b % P};
    }
    frac operator*(const int A)
    {
        return (frac){a * A % P, b % P};
    }
};
frac ans[1000001];
// 0 b, 1 r
// 0 = ,1 b>r ,2,b<r
int main()
{
    //freopen("brtree.in", "r", stdin);
    //freopen("brtree.out", "w", stdout);
    int p, q, T;
    scanf("%d%d%d%d", &p, &q, &T, &P);
    p %= P;
    q %= P;
    frac B = (frac){q - p, q};
    frac R = (frac){p, q};
    frac BR = B * R * 2;
    frac BBRR = (frac){p * p + (q - p) * (q - p), q * q};
    BR = BR.Update(BR);
    BBRR = BBRR.Update(BBRR);
    ans[2] = BBRR;
    for (int i = 4; i <= 1000000; i += 2)
    {
        ans[i] = ans[i - 2] * BR;
    }
    int k = 0, r = 0;
    while (T--)
    {
        scanf("%d", &k);
        k -= r;
        //int Gcd = ans[k].gcd(ans[k].a, ans[k].b);
        r = 0;
        printf("%lld %lld\n", ans[k].a % P, ans[k].b % P);
        r = ans[k].a % P;
    }
}
 
vijos 黑红树
https://www.nekomio.com/posts/46/
作者
NekoMio
发布于
2017-07-30
许可协议
CC BY-NC-SA 4.0