杭电数论入门习题

HDU 1973 Prime Path

这道题是一道从起点到终点的问题,很明显可以用广搜搜索最小步数即可,同理也可以用最短路,但是需要建边,时间复杂度低。

#include <cstdio>
#include <queue>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 10005;
bool prime[maxn],vis[maxn];
char a[5],b[5];

void init()            //生成素数表,不然每次都判断很耗时
{
    memset(prime, false, sizeof(prime));
    for(int i = 2; i < maxn; i++) if(!prime[i])
        for(int j = i*i; j < maxn; j += i)
            prime[j] = true;
}

struct Node        //这里我将整数当做字符串处理的,但是当整数处理可能操作会麻烦,但是时间更快
{
    char s[5];
    int step;
};

int bfs()
{
    queue <Node> que;
    Node pre,cur;
    memset(vis, false, sizeof(vis));
    memcpy(pre.s, a, sizeof(a));  //字符串复制函数
    pre.step = 0;
    que.push(pre);
    vis[atoi(a)] = true;         //atoi函数将字符串转化为整形
    while(!que.empty())
    {
        pre = que.front();
        que.pop();
        if(!strcmp(pre.s,b))
            return pre.step;
        for(int i = 0; i < 4; i++)
        {
            for(int j = 0; j < 10; j++)
            {
                if(!i && !j) continue; //最高位不改为0
                memcpy(cur.s, pre.s,sizeof(pre.s));
                cur.s[i] = j + '0';
                int temp = atoi(cur.s);
                if(!vis[temp] && !prime[temp])
                {
                    vis[temp] = true;
                    cur.step = pre.step + 1;
                    que.push(cur);
                }
            }
        }
    }
    return -1;
}

int main()
{
    int T;
    scanf("%d", &T);
    init();
    while(T--)
    {
        scanf("%s%s", a, b);
        int ans = bfs();
        if(ans == -1) printf("Impossible\n");
        else printf("%d\n", ans);
    }
    return 0;
}

HDU 1930 And Now, a Remainder from Our Sponsor

这道题看着麻烦,其实写起来还是挺简单的,有一些小细节还是需要处理的,比如一个6位数如何分割问题,还要最后剩余可能一个空格,后者2个空格的处理问题,详细看代码。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
char str[55][10];
int a[10],b[10],c[55];

void exgcd(int a, int b, int &x, int &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return;
    }
    exgcd(b, a % b, y, x);
    y -= (a/b)*x;
}

int CRT(int a[],int m[],int n)
{
    int M = 1;
    int ans = 0;
    for(int i=0; i<n; i++)
        M *= m[i];
    for(int i=0; i<n; i++)
    {
        int x, y;
        int Mi = M / m[i];
        exgcd(Mi, m[i], x, y);
        ans = (ans + Mi * x * a[i]) % M;
    }
    if(ans < 0) ans += M;
    return ans;
}

int main()
{
    int T,n;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        for(int i = 0; i < 4; i++)
            scanf("%d", &a[i]);
        for(int i = 0; i < n; i++)
            scanf("%d", &c[i]);
        for(int i = 0; i < n; i++)
        {
            for(int j = 3; j >= 0; j--)  //倒着求
            {
                b[j] = c[i]%100;
                c[i] /= 100;
            }
            int ans = CRT(b, a, 4);
            for(int j = 2 ; j >= 0; j--)
            {
                b[j] = ans%100;
                ans /= 100;
            }
            if(i != n-1)
            {
                for(int j = 0 ; j < 3; j++)
                    if(b[j] == 27) printf(" ");
                    else printf("%c", b[j]+'A'-1);
            }
            else    //最后的空格处理问题
            {
                if(b[2] == 27)
                {
                    b[2] = 0;
                    if(b[1] == 27)
                        b[1] = 0;
                }
                for(int j = 0 ; j < 3; j++)
                    if(b[j] == 27) printf(" ");
                    else if(b[j]) printf("%c", b[j]+'A'-1);
            }
        }
        printf("\n");
    }
    return 0;
}

HDU 1920 Jackpot

水题,求最小公倍数

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
int a[5];

int main()
{
    int n,m;
    while(scanf("%d", &n) != EOF)
    {
        while(n--)
        {
            scanf("%d", &m);
            for(int i = 1; i <= m; i++)
            scanf("%d", &a[i]);
            LL ans = 1,j;
            for(int i = 1; i <= m; i++)
            {
                for(j = 1; (j*ans)%a[i] != 0; j++);
                ans *= j;
                if(ans > 1000000000) break;
            }
            if(ans > 1000000000) printf("More than a billion.\n");
            else printf("%I64d\n", ans);
        }


  }
    return 0;
}

HDU 1788 Chinese remainder theorem again

这道题同样没什么难点,但是需要转化一下。N%M=(M-a)转化为(N+a)%M=0,因此同样成了求最小公倍数的问题。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;

int b[15];

int main()
{
    int I,a;
    while(scanf("%d%d", &I, &a) != EOF)
    {
        if(!I && !a) break;
        for(int i = 1; i <= I; i++)
            scanf("%d", &b[i]);
        LL ans = 1,j;
        for(int i = 1; i <= I; i++)
        {
            for(j = 1; (ans*j)%b[i]; j++);
                ans *= j;
        }
        printf("%I64d\n", ans - a);
    }
    return 0;
}

HDU 1787 GCD Again

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int euler(int n){
    int m = (int)sqrt(n+0.5);
    int ans = n;
    for(int i = 2; i <= m; i++) if(n % i == 0){
        ans = ans/i*(i-1);
        while(n % i == 0) n /= i;
    }
    if(n > 1) ans = ans/n*(n-1);
    return ans;
}

int main()
{
    int N;
    while(scanf("%d", &N) != EOF && N)
    {
        int ans = euler(N);
        printf("%d\n", N-1-ans);
    }
    return 0;
}

HDU 1452 Happy 2004

/*
设S(x)表示x的因子和。则题目求为:S(2004^X)mod 29
因子和S是积性函数,即满足性质1。

性质1 :如果 gcd(a,b)=1  则 S(a*b)= S(a)*S(b)
2004^X=4^X * 3^X *167^X
S(2004^X)=S(2^(2X)) * S(3^X) * S(167^X)

性质2 :如果 p 是素数 则 S(p^X)=1+p+p^2+...+p^X = (p^(X+1)-1)/(p-1)
因此:S(2004^X)=(2^(2X+1)-1) * (3^(X+1)-1)/2 * (167^(X+1)-1)/166
167%29 == 22
S(2004^X)=(2^(2X+1)-1) * (3^(X+1)-1)/2 * (22^(X+1)-1)/21

性质3 :(a*b)/c %M= a%M * b%M * inv(c)
其中inv(c)即满足 (c*inv(c))%M=1的最小整数,这里M=29
则inv(1)=1,inv(2)=15,inv(22)=15

有上得:
S(2004^X)=(2^(2X+1)-1) * (3^(X+1)-1)/2 * (22^(X+1)-1)/21
=(2^(2X+1)-1) * (3^(X+1)-1)*15 * (22^(X+1)-1)*18
*/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 29;

int sum(int a,int b)   //快速幂
{
    int ans = 1;
    while(b)
    {
        if(b&1) ans = (ans*a)%mod;
        a = (a*a)%mod;
        b = b>>1;
    }
    return ans;
}

int main()
{
    int X;
    while(scanf("%d", &X) != EOF && X)
    {
        int a,b,c;
        a = (sum(2,2*X+1)-1);
        b = (sum(3,X+1)-1);
        c = (sum(167,X+1)-1);
        printf("%d\n", (a*b*15*c*18)%29);
    }
    return 0;
}

HDU 1370 Biorhythms

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int MOD = 21252;

void exgcd(int a,int b,int &x,int &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
    }
    else
    {
        exgcd(b, a%b, y, x);
        y -= (a/b)*x;
    }
}

int CRT(int a[],int m[],int n)
{
    int M = 1;
    int ans = 0;
    for(int i = 0; i < n; i++)
        M *= m[i];
    for(int i = 0; i < n; i++)
    {
        int Mi = M/m[i];
        int x,y;
        exgcd(Mi, m[i], x, y);
        ans = (ans + Mi*x*a[i])%M;
    }
    if(ans < 0) ans += M;
    return ans;
}

int main()
{
    getchar();
    int a[5],m[5] = {23, 28, 33};
    int d,kase = 1;
    while(scanf("%d%d%d%d", &a[0], &a[1], &a[2], &d) != EOF)
    {
        if(a[0] == -1 && a[1] == -1 && a[2] == -1 && d == -1)
            break;
        int ans = CRT(a, m, 3);
        if(ans <= d) ans += MOD;
        printf("Case %d: the next triple peak occurs in %d days.\n", kase++, ans-d);
    }
    return 0;
}

HDU 1299 Diophantus of Alexandria

这道题非常需要转化,假设y = (n+k),则x = n*(n+k)/k;若n = p1 ^ e1 * p2 ^ e2 ……….*pn ^ en,则n的质因子为sum ( n)= ( 1 + e1 ) ( 1 +e2 ) * ………* ( 1 +en ),则n*n则质因子为( 1 + 2*e1 ) * ( 1 +2*e2 ) * ………* ( 1 +2*en ),这样就可以求解了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 4000;
bool isprime[maxn];
int prime[maxn];

int init()
{
    int cnt = 0;
    memset(isprime, 0, sizeof(isprime));
    for(int i = 2; i < maxn; i++)if(!isprime[i])
        for(int j = i*i; j < maxn; j += i)
            isprime[j] = true;
    for(int i = 2; i < maxn; i++)
        if(!isprime[i]) prime[cnt++] = i;
    return cnt;
}

int main()
{
    int T,cnt,n;
    scanf("%d", &T);
    cnt = init();
    for(int kase = 1; kase <= T; kase++)
    {
        scanf("%d", &n);
        LL sum = 1;
        int temp = n;
        for(int i = 0; i < cnt && prime[i] < temp; i++)
        {
            int ans = 0;
            while(n % prime[i] == 0)
            {
                n /= prime[i];
                ans++;
            }
            sum *= (2*ans+1);
        }
        if(n > 1) sum *= 3;  //比如当n等于2的时候
        printf("Scenario #%d:\n%I64d\n\n", kase, (sum+1)/2);
    }
    return 0;
}

HDU 1719 Friend

假设Fn=a*b+a+b,转化可得Fn+1 = (a+1)*(b+1),又因为a,b的初始值为1,2,因此对于每一个成立的数n,n+1能整除2或者3.注意要考虑n为0的情况。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
        if(!n)
        {
            printf("NO!\n");
            continue;
        }
        n++;
        while(n%2 == 0) n /= 2;
        while(n%3 == 0) n /= 3;
        if(n == 1) printf("YES!\n");
        else printf("NO!\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值