数论 练习题【题解】

24 篇文章 0 订阅
12 篇文章 0 订阅

1.M斐波那契数列

Description

M斐波那契数列F[n]是一种整数数列,它的定义如下:
F[0] = a
F[1] = b
F[n] = F[n-1] * F[n-2] ( n > 1 )
现在给出a, b, n,你能求出F[n]的值吗?

Input

第一行,包含3个整数a, b, n( 0 <= a, b, n <= 10^9 )

Output

输出一个整数F[n],由于F[n]可能很大,你只需输出F[n]对1000000007取模后的值即可。

Sample Input

6 10 2

Sample Output

60


Solution:

枚举几项:

N表达式
0 a
1 b
2 ab
3 ab2
4 a2b3
5 a3b5
6 a5b8

所以就会发现,a,b的指数是呈斐波那契数列的关系
F(n)=af(n)bf(n+1)mod p
这样问题就简单了,由于n会很大,所以可以用矩阵乘法加速递推,a%p的运算用费马小定理
Code:

#include <stdio.h>
#include <string.h>
#define MOD 1000000007
typedef long long ll;
struct matrix
{
    ll a[3][3];
}v,ans;
ll a,b,n;
ll quick_pow(ll x,ll y)
{
    ll ans=1;
    x=x%MOD;
    while(y)
    {
        if(y%2==1)
        {
            ans=(ans*x)%MOD;
        }
        y/=2;
        x=(x*x)%MOD;
    }
    return ans;
}
void init()
{
    memset(ans.a,0,sizeof(ans.a));
    ans.a[0][0]=ans.a[1][1]=ans.a[2][2]=1;
    v.a[0][0]=v.a[0][1]=v.a[1][0]=1,v.a[1][1]=0;
}
matrix mul(matrix x,matrix y)
{
    matrix tmp;
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            tmp.a[i][j]=0;
            for(int k=0;k<3;k++)
            {
                tmp.a[i][j]+=(x.a[i][k]*y.a[k][j]);
                tmp.a[i][j]%=(MOD-1);   //给幂取模要取(MOD-1) 
            }
        }
    }
    return tmp;
}
void cal(ll n)
{
    while(n)
    {
        if(n&1)
        {
            ans=mul(ans,v);
        }
        n>>=1;
        v=mul(v,v);
    }
}
int main()
{
    init();
    scanf("%lld%lld%lld",&a,&b,&n);
    init();
    if(a==0||b==0)
    {
        puts("0");
        return 0;
    }
    cal(n-1);       
    ll p=quick_pow(a,ans.a[0][1]);
    ll q=quick_pow(b,ans.a[0][0]);
    printf("%lld\n",((p%MOD)*(q%MOD))%MOD);
    return 0;
}

2.Genius

Solution:

因为题中要求的约数包括1和该数本身,所以对于一个数的约数倒数和通分之后的分母就是这个数本身(也就是题中的A),而分子是约数和。
所以可以得到下面的式子:
AN=B1B2 N= AB2B1
所以只需要判断 AB2B1 是否整除,如果整除,求出N后看其约数和是否等于A即可.
Code:

#include <stdio.h>
#include <string.h>
typedef long long ll;
ll a,b1,b2,n;
ll count(ll num)
{
    ll cnt=0;
    for(ll i=1;i<=num;i++)
    {
        if(num%i==0)
        {
            cnt+=i; 
        }
    }
    return cnt;
} 
int main()
{
    freopen("genius.in","r",stdin);
    freopen("genius.out","w",stdout);
    while(~scanf("%lld%lld%lld",&a,&b1,&b2)&&a&&b1&&b2)
    {
        if((a*b2)%b1!=0)
        {
            puts("0");
            continue;
        }
        n=(a*b2)/b1;
        if(count(n)==a)
        {
            printf("1 %lld\n",n);
        }
        else printf("0\n");
    }   
    return 0;
}

3.Count Path Pair

Time Limit: 3 Seconds Memory Limit: 65536 KB

Description:

You are given four positive integers m,n,p,q(p < m and q < n). There are four points A(0,0),B(p,0),C(m,q),D(m,n). Consider the path f from A to D and path g from B to C. f and g are always towards and parallel to the positive direction of one axis, and they can only change their direction on integer points(whose coordinates are both integers).

You are asked to count the number(mod 100000007) of pair (f,g) that f and g have no intersection.

Input

There are multiple cases(less than 100). Each case is a line containing four integers m,n,p,q(m ≤ 100000 and n ≤ 100000).

Output

For each case, output a single line containing the right answer.

Sample Input

2 2 1 1
3 2 1 1

Sample Output

3
6


Translation:

4个点A(0,0),B(p,0),C(m,q),D(m,n),保证m>p,n>q,求从A走到D和从B走到C两条路径不相交的走法的种数,只能up和right。

Solution:

补集转化的思想,不相交的走法相当于所有的走法减去相交的走法。
而我们又知道从A到C和从B到D路径必相交,所以就可以用C(n+m,n) * C(m-p+q,q) - C(m+q,q) * C(m+n-p,n)来求得答案。
而对于组合数取模已经都很熟悉了。
Code:

#include <stdio.h>
#define mod 100000007
typedef long long ll;
ll n,m,p,q;
ll x=1,y=0;
ll ret;
ll suma,sumb;
ll ans_a,ans_b,ans_c,ans_d;
void Exgcd(ll a,ll b)
{
    if(b==0)
    {
        x=1;
        y=0;
    }
    else
    {
        Exgcd(b,a%b);
        ll t=x;
        x=y;
        y=t-a/b*x;
    }
}
void mulipy(ll n,ll m)
{
    for(ll i=m+1;i<=n;i++)
    {
        suma*=i;
        suma=suma%mod;
        sumb*=i-m;
        sumb=sumb%mod;
    }
}
ll get(ll n,ll m)
{
    suma=sumb=1;
    mulipy(n,m);
    Exgcd(sumb,mod);
    x=(x%mod+mod)%mod;
    long long ans=(x*suma)%mod;
    return ans;
}
void f(ll num)
{
    num%=mod;
}
int main()
{
    while(scanf("%lld%lld%lld%lld",&m,&n,&p,&q)!=EOF)
    {
        ans_a=get(n+m,n);   f(ans_a);
        ans_b=get(m-p+q,q); f(ans_b);
        ans_c=get(m+q,q);   f(ans_c);
        ans_d=get(m+n-p,n); f(ans_d);
        printf("%lld\n",((ans_a*ans_b)%mod-(ans_c*ans_d)%mod+mod)%mod);
    }
    return 0;
}

4.Poj1365【Prime Land】

POJ1365传送门
题意就是给你一个数分解质因数的形式之后,求出这个数减一的分解质因数的形式。
除了读入麻烦外剩下就是裸题。
Code:

#include <stdio.h>
#include <string.h>
#define MAXN 100000
int ans,k;
int cnt[MAXN];
int prime[MAXN];
char s[MAXN];
int quick_pow(int x,int y)
{
    int ans=1;
    while(y)
    {
        if(y%2==1)
        {
            ans=(ans*x);
        }
        y/=2;
        x=(x*x);
    }
    return ans;
}
void div(int n)
{
    memset(prime,0,sizeof(prime));
    memset(cnt,0,sizeof(cnt));
    k=1;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            prime[k]=i;
            while(n%i==0)
            {
                cnt[k]++;
                n/=i;
            }
            k++;
        }
    }
    if(n!=1)
    {
        prime[k]=n;
        cnt[k++]=1;
    }
}
int main()
{
    while(1)
    {
        ans=1;
        gets(s);
        if(s[0]=='0')
        {
            break;
        }
        int len=strlen(s),tmp=0,t=0,x,y;
        for(int i=0;i<=len;i++)
        {
            if(s[i]==' '||s[i]=='\0')
            {
                t++;
                if(t%2==1)  x=tmp;
                else
                {
                    y=tmp;
                    ans=ans*quick_pow(x,y); 
                }
                tmp=0;
                continue;
            }
            tmp=tmp*10+(s[i]-'0');
        }
        ans--;
        div(ans);
        for(int i=k-1;i>=1;i--)
        {
            printf("%d %d ",prime[i],cnt[i]);
        }
        printf("\n");
    }
    return 0;
}

5.SPOJ10568【Finding Fractions 】

Description

Given a,b,c,d, find a fraction p/q with minimum q, and satisfied a/b < p/q < c/d .

Input

For each test case, one line contains four integers a,b,c,d .

Output

For each test case, print the fraction(see the sample for details).If multiple solution exists, output the one with minimum p.

Example

Input:

1 3 1 2
2 1 3 1
2 1 4 1
1000 1001 1001 1002

Output:

2/5
5/2
3/1
2001/2003

Constraints

Dataset 1: a,b,c,d ( 1 <= a,b,c,d <= 1e9, and a/b < c/d )

Hint

Added by: Race with time
Date: 2009-02-19
Time limit: 3s
Source limit: 50000B
Memory limit: 1536MB
Cluster: Cube (Intel Pentium G860 3GHz)
Languages: All except: ERL JS NODEJS PERL 6 VB.net
Resource: Code Craft 09


Solution:

神犇题解:Click Here!
连分数解法:
设[a/b]表示a/b向下取整
如果a/b >= 1,设k = [a/b],可以知道 ( a/b ) - k < ( p/q ) - k < ( c/d ) - k,即 (a-bk)/b < (p - qk)/q < ( c- dk) / d,设a’ = a - bk,p’ = p - qk,c’ = c - dk,则求出a’/b < p’/q < c’/d的解以后,p = p’ + qk,可以得到真实的p和q。
如果a/b<1
如果c/d>1,那么p = q = 1
如果c/d<=1,那么问题可以转化为d/c < q/p < b/a
Code:

#include <stdio.h>
#include <string.h>
typedef long long ll; 
ll a,b,c,d;
ll find(ll a,ll b,ll c,ll d)
{
    if(a<b)
    {
        if(c>d) return 1;  
        else return find(d,c,b,a)*d/c+1;  
    }
    else
    {
        int k=a/b;
        return find(a-k*b,b,c-k*d,d);  
    }
}
int main()
{
    while(~scanf("%lld%lld%lld%lld",&a,&b,&c,&d))
    {
        ll q=find(a,b,c,d);
        ll p=q*a/b+1;
        printf("%lld/%lld\n",p,q);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由于题目没有具体说明是哪个作业的练习题,因此无法提供准确的答案。数论是关于整数性质与结构的研究,涉及到整数的基本性质,因此答案需要根据具体的题目来给出。以下是一些数论导引练习题的一般解答方法: 1. 证明素数无穷多个: 答案:假设素数只有有限个,标记为p1, p2, ..., pn。然后构造一个新的数q,q = p1p2...pn +1。由于1不是素数,所以q一定是一个素数。这样我们得到了比已知的所有素数都大的素数q,与假设矛盾,因此素数无穷多个。 2.证明方程x^2 + y^2 = z^2 在正整数解中有无穷多个: 答案:首先,我们可以构造一个简单的解(x,y,z) = (3,4,5)。然后考虑将这个解乘以一个正整数k得到新的解(x',y',z')=(3k,4k,5k)。由于k是任意的正整数,所以可以构造出无穷多个解。因此,方程在正整数解中有无穷多个。 3.证明质数的乘积加一不是素数: 答案:假设质数的乘积加一是一个素数,标记为p。然后考虑将p减去1,得到p-1。根据欧拉定理,如果p是一个质数,那么p-1一定能被p的某一个质因数整除。但由于p-1是p的倍数,所以p也能整除p-1,这与p是一个素数矛盾。因此,质数的乘积加一不是素数。 总之,数论是一个广泛而深入的领域,需要具体问题具体分析,根据题目中给出的具体条件进行推导和证明。以上是一些常见的解答方法,但无法确定具体的题目,所以答案可能不是完整的或不适用于特定的练习题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值