题目描述
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
2
样例输出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 "); la=0; continue; } if(qu&1) { printf("0 0 "); 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 ",afz,afm); la=afz; } //while(1); return 0; }