黑红树

题目描述

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

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

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

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

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

4、 黑红树上的高度这样定义:h(根节点)=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
0 0 
5 9

样例输入2

2 3 2 20

4

6

样例输出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

 

【题解】

    每日一道概率题。非常愉快的调出来10分,在考试过程中打了分数加减乘约分,简直360度复习小学知识,虽然调试过程中发现了一些规律但是并没有什么用,没有再往下一步走。虽然题目叫黑红树,可是和某数据结构好像毫无关系。每日一跳的推式子大坑,但是我推的还是不够优美,实现也很虚,除了某ryf大佬A掉之外也只有本蒟蒻水了十分,膜一发大佬。

    正解用到两个概率,在每两层不掉下的概率(p^2+(p-q)^2)/q^2,掉下的概率自然是1-不掉下概率。为什么都以两次为度量?在奇数层是不可能掉下去的,因为奇数层一定从红黑点相等的偶数层转移过来,至多差1个。这样只要询问的是奇数层就直接输出0 0,偶数层结果为不掉下概率^(层数/2-1)*掉下概率。在一切递推开始之前就把两个概率约到最简,之后就可以放心取模了。小学做作业的时候天天念着的规律,这么多年还真有些忘了啊。

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int sj=1000010;
int p,q,ca,k,ww;
long long qu,jz,a,b,c,d,fmf[sj],fzf[sj],afz,afm,la;
long long gcd(long long x,long long y)
{
    if(!y) return x;
    return gcd(y,x%y);
}
void yf(long long &x,long long &y)
{
    long long temp=gcd(x,y);
    if(temp!=1&&temp!=0)
    {
       x/=temp;
       y/=temp;
    }
}
void dt()
{
     for(int i=jz+1;i<=la;i++)
     {
        fmf[i]=fmf[i-1]*d%k;
        fzf[i]=fzf[i-1]*c%k;
     }
     jz=la;
}
int main()
{
    //freopen("t2.txt","r",stdin);
    //freopen("brtree1.in","r",stdin);
    //freopen("brtree.out","w",stdout);
    scanf("%d%d%d%d",&p,&q,&ca,&k);
    ww=q-p;
    a=p*p+ww*ww;
    b=q*q;
    d=b;
    c=b-a;
    yf(c,d);
    yf(a,b);
    fmf[1]=d;
    fzf[1]=c;
    fmf[0]=1;
    fzf[0]=1;
    jz=1;
    for(int i=1;i<=ca;i++)
    {
       scanf("%lld",&qu);
       qu-=la;
       if(qu<=0)  
       {
         printf("0 0\n");
         la=0;
         continue;
       }
       if(qu&1)
       {
         printf("0 0\n");
         la=0;
         continue;
       }
       la=(qu>>1)-1;
       if(jz<la) dt();
       afm=fmf[la]*b;
       afz=fzf[la]*a;
       afz%=k;
       afm%=k;
       printf("%lld %lld\n",afz,afm);
       la=afz;
    }
    //while(1);
    return 0;
}

 

posted @ 2017-07-28 21:20  moyiii  阅读(270)  评论(0编辑  收藏  举报