码迷,mamicode.com
首页 > 其他好文 > 详细

数论 练习题【题解】

时间:2015-08-11 14:13:24      阅读:305      评论:0      收藏:0      [点我收藏+]

标签:数论   题解   推荐   noip   

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=A?B2B1
所以只需要判断A?B2B1是否整除,如果整除,求出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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

数论 练习题【题解】

标签:数论   题解   推荐   noip   

原文地址:http://blog.csdn.net/z_mendez/article/details/47404355

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!