武大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 }

 

posted on 2018-08-29 12:12  怡红公子  阅读(246)  评论(0编辑  收藏  举报