武大OJ 613. Count in Sama’s triangle
Description
Today, the math teacher taught Alice Hui Yang’s triangle. However, the teacher came up with a new one, called Sama’s triangle (some of you may be familiar with this name).
In this triangle, there is only 30 row, and the ith row has i-1 number, f[i][1] , f[i][2], …, f[i][i-1] (1strow has no number). And initially, f[i][0] = a, f[i][i] = b, (0<a, b) then f[i][j] = f[i-1][j-1] + f[i-1][j] (for all i from 1 to 30 , for all j in 1 to i-1, inclusive).
2ndrow f[2][1]
3rdrow f[3][1] f[3][2]
4throw f[4][1] f[4][2] f[4][3]
30throw f[30][1] f[30][2] f[30][3] … f[30][29]
Now the teacher asked, ‘how many M are in the triangles among all pairs of (a, b).
Input
The input consists of several test cases.
The first line consists of one integer T (T <= 500), meaning the number of test cases.
For each test cases, there is one integer M (M<= 1e9), which is asked from the teacher.
Here, 1eX means 1000…0000 (x 0s).
Output
For each test case, output the times number M shows up in all positions of all triangles.
Sample Input
1 3
Sample Output
4
每个位置的数可以用一个二元一次函数表示𝑥∗𝑎+𝑦∗𝑏
然后通过dp计算435个数对应的𝑥和𝑦
剩下的就是求𝑥∗𝑎+𝑦∗𝑏=𝑚这个不定方程的正整数解数量
扩展欧几里得完美解决,先计算x*a1+y*b1=m,a1是满足条件的大于0的最小整数,然后a1+=y/gcd(x,y),b1-=x/gcd(x,y),a1是永远大于0的,所以只需要判断b1
时间复杂度:O(logM)
1 #include<iostream> 2 #include<stdio.h> 3 #include<math.h> 4 #include<stdlib.h> 5 using namespace std; 6 7 typedef struct{ 8 long long a,b; 9 }Point; 10 Point p[31][31]; 11 long long m; 12 int t; 13 14 void gcd_extend(int a,int b,int& x,int& y,int& gcd){ 15 if(a<b) 16 { 17 gcd_extend(b,a,y,x,gcd);return ; 18 } 19 20 if(b==0) {x=1;y=0;gcd=a;return ;} 21 gcd_extend(b,a%b,x,y,gcd); 22 23 int xx=y,yy=x-(a/b)*y; 24 x=xx;y=yy; 25 return ; 26 } 27 28 int main() 29 { 30 scanf("%d",&t); 31 for(int i=1;i<=30;++i) 32 { 33 for(int j=0;j<=i;++j) 34 { 35 if(j==0) {p[i][j].a=1;p[i][j].b=0;continue;} 36 if(j==i) {p[i][j].a=0;p[i][j].b=1;continue;} 37 p[i][j].a=p[i-1][j-1].a+p[i-1][j].a; 38 p[i][j].b=p[i-1][j-1].b+p[i-1][j].b; 39 } 40 } 41 42 long long ans=0; 43 while(t>0) 44 { 45 t--; 46 scanf("%lld",&m); 47 ans=0; 48 for(int i=1;i<=30;++i) 49 for(int j=1;j<i;++j) 50 { 51 int x=0,y=0,gcd=0; 52 gcd_extend(p[i][j].a,p[i][j].b,x,y,gcd); 53 if(m%gcd!=0) continue; 54 55 56 //找a*x+b*y=m的大于零的最小的x 57 x=x*m/gcd;y=y*m/gcd; 58 int t=p[i][j].b/gcd; 59 x=(x%t+t)%t; 60 y=(m-p[i][j].a*x)/p[i][j].b; 61 62 while(x<=0) 63 {x+=p[i][j].b/gcd;y-=p[i][j].a/gcd;} 64 65 66 //x增加b/gcd,y减小计a/gcd,计算有多少个满足条件的y 67 int count=0; 68 if(y>0) 69 { 70 count+=y/(p[i][j].a/gcd)+1; 71 if(y%(p[i][j].a/gcd)==0) count--; 72 } 73 ans+=count; 74 75 76 } 77 cout<<ans<<endl; 78 79 } 80 81 82 83 84 85 }