黑红树
背景
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
样例输入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
solution:
解法1:
考试时想的(能过8个点,手动开O3能A)
把图全画出来,你会得到一个通项公式:
f[i]=( (2*p*(q-p))^(h/2-1) * (2*p^2-2*q*p+q^2) ) / q^h
=0 (h为奇数)
然后分解质因数约分即可
解法2:
我们发现h为奇数时只有可能 abs(黑点数-红点数)=1,所以 f[h]=0
当h为偶数时,
我们发现 (p/q)+(1+p/q)=(p^2+(q-p)^2)/q^2 为走两个高度时不掉的概率 而 1-(p^2+(q-p)^2)/q^2=2*p(q-p)/q^2 是掉的概率
我们设 掉概率分子为A,分母为B 不掉概率分子为C,分母为D
f[h]= 0 h为奇数
= C^(h/2-1)*A / (B^2)^(h/2-1)*(D^2)
至于约分只要在一开始把A和B,C和D的约数约掉即可
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #define ll long long 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 using namespace std;//5137 8 int maxn(int a,int b){return a>b?a:b;} 9 int abss(int x){return x<0?-x:x;} 10 const int Max=50050; 11 12 int prime[100001],num; 13 bool he[100001]; 14 15 __attribute__((optimize("O3"))) void PRIME() 16 { 17 int q1=(int)ceil(sqrt(Max)); 18 for(int i=2;i<=Max;++i) 19 { 20 if(he[i])continue; 21 prime[++num]=i; 22 for(int j=i*2;j<=Max;j+=i) 23 he[j]=1; 24 } 25 } 26 27 28 29 int p,q,k,m; 30 int h; 31 ll a,b; 32 33 __attribute__((optimize("O3"))) ll mi(ll x,ll c) 34 { 35 ll ans=1; 36 while(c) 37 { 38 if(c&1) 39 ans=ans*x%k; 40 x=x*x%k; 41 c>>=1; 42 } 43 return ans; 44 } 45 46 int azhi[5201],bzhi[5201]; 47 /*void out11() 48 { 49 printf("\n"); 50 for(int i=1;i<=20;++i) 51 printf("%d ",azhi[i]); 52 printf("\n"); 53 for(int i=1;i<=20;++i) 54 printf("%d ",bzhi[i]); 55 printf("\n"); 56 }*/ 57 __attribute__((optimize("O3"))) void qq() 58 { 59 if(h&1||h==0) 60 { 61 a=0; 62 b=0; 63 return ; 64 } 65 mem(azhi,0); 66 mem(bzhi,0); 67 int ci=h/2-1; 68 int q1=2*q*q-2*p*q+p*p; 69 int q2=2*q*(p-q); 70 int q3=p; 71 //printf("ci=%lld q1=%lld q2=%lld q3=%lld\n",ci,q1,q2,q3); 72 int maxl=0; 73 //cout<<1; 74 int now=0; 75 while(q2!=1) 76 { 77 ++now; 78 while(!(q2%prime[now])) 79 { 80 q2/=prime[now]; 81 ++azhi[now]; 82 } 83 azhi[now]*=ci; 84 } 85 maxl=maxn(maxl,now); 86 87 now=0; 88 while(q1!=1) 89 { 90 ++now; 91 while(!(q1%prime[now])) 92 { 93 q1/=prime[now]; 94 ++azhi[now]; 95 } 96 } 97 maxl=maxn(maxl,now); 98 99 now=0; 100 while(q3!=1) 101 { 102 ++now; 103 while(!(q3%prime[now])) 104 { 105 q3/=prime[now]; 106 ++bzhi[now]; 107 } 108 bzhi[now]*=h; 109 } 110 maxl=maxn(maxl,now); 111 112 for(int i=1;i<=maxl;++i) 113 { 114 if(azhi[i]>bzhi[i]){azhi[i]-=bzhi[i];bzhi[i]=0;} 115 else{bzhi[i]-=azhi[i];azhi[i]=0;} 116 } 117 //out11(); 118 a=1;b=1; 119 for(int i=1;i<=maxl;++i) 120 { 121 if(azhi[i]) 122 a=(a*(mi(prime[i],azhi[i])%k))%k; 123 if(bzhi[i]) 124 b=(b*(mi(prime[i],bzhi[i])%k))%k; 125 } 126 } 127 128 __attribute__((optimize("O3"))) int main(){ 129 //freopen("1.txt","r",stdin); 130 //freopen("brtree7.in","r",stdin); 131 //freopen("brtree.out","w",stdout); 132 PRIME(); 133 //printf("num=%d\n",num); 134 //out11(); 135 scanf("%d%d%d%d",&q,&p,&m,&k); 136 137 while(m--) 138 { 139 scanf("%d",&h); 140 h-=a%k; 141 qq(); 142 //printf("caocoaca\n"); 143 printf("%lld %lld\n",a,b); 144 } 145 //printf("\nend\n"); 146 //while(1); 147 return 0; 148 }
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #define ll long long 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 using namespace std; 8 ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);} 9 10 ll a[1000010],b[1000010]; 11 ll q,p,m,k,h; 12 13 int main(){ 14 //freopen("brtree4.in","r",stdin); 15 //freopen("2.txt","w",stdout); 16 scanf("%lld%lld%lld%lld",&p,&q,&m,&k); 17 //C:fall 18 ll A=2*p*(q-p),B=q*q,C=2*p*p-2*p*q+q*q,D=q*q; 19 while(1) 20 { 21 ll hh=gcd(A,B); 22 if(hh==1)break; 23 A/=hh;B/=hh; 24 } 25 while(1) 26 { 27 ll hh=gcd(C,D); 28 if(hh==1)break; 29 C/=hh;D/=hh; 30 } 31 ll nowa=1,nowb=1; 32 for(int i=2;i<=1000000;i+=2) 33 { 34 a[i]=nowa*C%k; 35 b[i]=nowb*D%k; 36 nowa=nowa*A%k; 37 nowb=nowb*B%k; 38 } 39 40 //printf("%lld %lld\n",a[1000000],b[1000000]); 41 42 ll aa=0,bb=0; 43 while(m--) 44 { 45 scanf("%lld",&h); 46 h-=(aa%k); 47 //printf("h=%d\n",h); 48 aa=a[h];bb=b[h]; 49 printf("%lld %lld\n",aa,bb); 50 } 51 //while(1); 52 return 0; 53 }