分享
分销 收藏 举报 申诉 / 11
播放页_导航下方通栏广告

类型ACM数论方面十道基础题目详解.docx

  • 上传人:pc****0
  • 文档编号:5960334
  • 上传时间:2024-11-24
  • 格式:DOCX
  • 页数:11
  • 大小:36.26KB
  • 下载积分:10 金币
  • 播放页_非在线预览资源立即下载上方广告
    配套讲稿:

    如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。

    特殊限制:

    部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。

    关 键  词:
    ACM 数论 方面 基础 题目 详解
    资源描述:
    1、 公约数和公倍数 这道题目是非常基础的题目,在学习了欧几里德算法之后,应该很好就能做的出来了。注意两个数的最小公倍数和最大公约数之间有关系为:a*b=gcd(a,b)*lcm(a,b); 代码如下: #include<iostream> using namespace std; inline int Gcd(int m,int n) //求最大公约数 { if (m==0) return n; return Gcd(n%m,m); } int main() { int n,a,b,g; cin>>n; while(n--) { cin>>a>>b; g=Gcd(a,b); cout<<g<<" "<<a*b/g<<endl; } } 2、 Biorhythms 很经典的中国剩余问题。 题目大意是:人的体力、情绪和智力都是有周期的,分别是23天、28天和33天。分别给出你体力、情绪和智力最高值过后的天数p、e、d,然后让你计算下一次三者同时达到最高值的时间。 那么再次达到最高值时间为n,则有: 那么找到k1、k2、k3满足: k1:k1%23==0&&k1%28==0&&k1%33==1 k2:k2%33==0&&k2%28==0&&k2%23==1 k3:k3%33==0&&k3%23==0&&k3%28==1 则n=k2*p+k3*e+k1*i+k*21252; 代码如下: #include <stdio.h> int main() { int n,a,b,c,t; while(scanf("%d%d%d%d",&a,&b,&c,&t),~a) { n=(5544*a+14421*b+1288*c)%21252-t; if(n<=0) n+=21252; printf("%d\n",n); } } 3、 韩信点兵 这个题目也是很经典的中国剩余问题类的题目,思路跟上面差不多这道题目因为数据范围很小实际上暴力就可以过,但是这个题目不失为练习中国剩余的很好题目,所以建议大家用中国剩余定理做一下。 直接给出代码: 暴力求解代码: #include <stdio.h> main() { int a,b,c,n; scanf("%d%d%d",&a,&b,&c); for(n=11;n<100;n++) if(n%3==a&&n%5==b&&n%7==c) printf("%d\n",n); } 中国剩余定理思路代码: #include<stdio.h> int main() { int a,b,c,m; scanf("%d %d %d",&a,&b,&c); m=(70*a+21*b+15*c)%105; printf("%d\n",m); return 0; } 4、 次方求模 这个题目是要求出a的b次方对c取余的值。 显然我们不能求出a^b后再对c取余,a^b可能是一个很大的数,而且这样做肯定很慢。那么我们利用同余定理来解决这个问题。 当然最简单的我们会想到:a^b%c=((a^(b-1)%c)*(a%c))%c; 但是这样效率依然是很低的。 那么我们考虑一种叫做二分快速幂的思路。 关键改进就是:a^b%c=((a^(b/2)%c)* (a^(b/2)%c))%c 比如我们要算3^25%4的值,由于25=1+8+16,那么我们就只需要知道3^1,3^8,3^16的值。这样复杂度就从O(n)降低为O(log(n))了。 代码实现如下: #include <iostream> using namespace std; int mod(int k,int x,int c) { int a=1; long long r=k; while(x) { if(x&1) a=(a*r)%c; r=((r%c)*(r%c))%c; x=x>>1; } return a; } int main() { int n,a,b,c; cin>>n; while(n--) { cin>>a>>b>>c; cout<<mod(a,b,c)<<endl; } } 5、 青蛙的约会 http://poj.org/problem?id=1061 这道题目用到了扩展欧几里德算法。 设过s步后两青蛙相遇,则必满足以下等式:(x+m*s)-(y+n*s)=k*l(k=0,1,2....) 稍微变一下形得:(n-m)*s+k*l=x-y 令n-m=a,k=b,x-y=c,即a*s+b*l=c 只要上式存在整数解,则两青蛙能相遇,否则不能。 这样问题就转化为了扩展欧几里德问题了。 代码如下: # include <stdio.h> __int64 gcd(__int64 a,__int64 b) {        if(b==0)               return a;        return gcd(b,a%b); } void exgcd(__int64 a,__int64 b,__int64 &m,__int64 &n) {        if(b==0)        {               m=1;               n=0;               return ;        }        exgcd(b,a%b,m,n);        __int64 t;        t=m;        m=n;        n=t-a/b*n; } int main() {        __int64 x,y,m,n,l,a,b,c,k1,k2,r,t;        while(scanf("%I64d%I64d%I64d%I64d%I64d",&x,&y,&m,&n,&l)!=EOF)        {               a=n-m;               b=l;               c=x-y;               r=gcd(a,b);               if(c%r)               {                      printf("Impossible\n");                      continue;               }               a/=r;               b/=r;               c/=r;               exgcd(a,b,k1,k2);               t=c*k1/b;//注1               k1=c*k1-t*b;               if(k1<0)                      k1+=b;               printf("%I64d\n",k1);        }        return 0; } 6、 Least Common Multiple 这道题目是要求出多个数的最小公倍数,求n个数的最小公倍数我们最容易想到的思路就是求出两个数的最小公倍数,然后再用这个最小公倍数与第三个数球最小公倍数,依次下去就可以求出n个数的最小公倍数了。至于两个数的最小公倍数我们从上面的习题中已经可以知道方法了。 a*b=gcd(a,b)*lcm(a,b); 那么我们考虑这种方法的复杂度,会发现我们要求出n个数的gcd,那么我们又更好的选择吗?是的,想想我们小学时间最开始学习最小公倍数小、最大公约数的时候,那时间我们是怎么求的呢?我们采用了一种叫做短除法的算法。 示例如下: 2|__12______16_______24__ 2| 6 8 12 2| 3 4 6 此时我们发现3 、4、 6是互质的,所以12、16、24的最小公倍数就是 2*2*2*3*4*6=576 当然这种方法的代码难度会略高于上一种思路。 附上代码(第一种思路): #include <stdio.h> int gcd(int x,int y) { return x?gcd(y%x,x):y; } int main() { int i,j,n,m,ret,tem; scanf("%d",&n); while(n--) { scanf("%d",&m); scanf("%d",&ret); m--; while(m--) { scanf("%d",&tem); ret=ret/gcd(ret,tem)*tem; } printf("%d\n",ret); } } 7、 C Looooops http://poj.org/problem?id=2115 扩展欧几里德,不是太裸的题目: 意思是输入4个数:a, b, c, k;(0<=a, b, c<2^k, 1=<k<=32) 计算是否存在x,使(a+c*x )≡ b(mod 2^k);如果存在输出x,否则输出FOREVER; 思路:首先知道存在temp使(a+temp)≡ b(mod 2^k);可得,temp = (b-a)%(2^k);现在问题是计算是否存在x,使x*c ≡ temp(mod 2^k);也就是求x*c-(x*c/(2^k)) * 2^k = temp - (temp/2^k) * 2^k; 既x*c-(x*c/(2^k) - temp / (2^k))*(2^k) = temp;既x*c-y*(2^k) = temp;因为c, k, temp都以知,(就是二元一次方程组(a*x0+b*y0=c的形式,知道如果(GCD(a, b)若不能整除c,可以判断方程无解)) 现在问题是计算x,计算gcd = gcd(c, 2^k),先判断是否有解; 若有解,方程两边除以gcd:因为gcd(c/gcd, 2^k/gcd)= 1,所以用扩展欧几里德算法可求出: x0*(c/gcd) + y0*(2^k/gcd) = 1;因此两边乘以temp/gcd得x*(c/gcd) + y*(2^k/gcd) = temp/gcd. 此x就是满足题目(x*c ≡ temp(mod 2^k))的解。 代码: #include <cstdio> long long extended_gcd(long long a, long long b, long long &x, long long &y) { long long ret, tmp; if (!b) { x = 1, y = 0; return a; } ret = extended_gcd(b, a % b, x, y); tmp = x; x = y; y = tmp - a / b * y; return ret; } long long modular_linear_equation(long long a, long long b, long long n) { long long x, y, e; long long d = extended_gcd(a, n, x, y); if (b % d) return -1; e = b / d * x % n + n; return e % (n / d); } int main() { long long a, b, c, ans; int k; while (scanf("%lld %lld %lld %d", &a, &b, &c, &k) == 4) { if (a == 0 && b == 0 && c == 0 && k == 0) break; ans = modular_linear_equation(c, b - a, 1LL << k); if (ans == -1) puts("FOREVER"); else printf("%lld\n", ans); } return 0; } 8、 兔子的烦恼(一) 这个题目其实也是很简单的。模拟就能过,但是用些数论的知识会很快的解决掉的。 分析:当n,m的最大公约数大于1,设最大公约数是k,不妨设m=a*k,n=b*k,那么第一轮进入的洞是0,m,2m,...(x-1)*m(不妨假设x*m>n,(x-1)*m<n.)。那么下一轮第一个是 x*m%n, 而x*m%n=x*a*k-b*k=(x*a-b)*k ,即说明下一轮开始的第一个也是k的倍数,而 k>1,所以狼没办法遍历所有的洞,于是兔子躲过一劫! 当n,m的最大公约数等于1,即互质,刚开始的证明同上,而k=1,说明狼可以遍历所有的洞,说得更白话点:只要洞口号是1的倍数,狼就可以进去。于是兔子就成了狼的美味了! 代码: #include<stdio.h> int gcd(int y,int x) { return x?gcd(x,y%x):y; } int main() { int m,n; while(scanf("%d%d",&m,&n)!=EOF) { if(gcd(m,n)==1) printf("NO\n"); else printf("YES\n"); } } 9、 兔子的烦恼(二) 这道题目同上面的题目差不多,只是比上面的略微复杂一点,思路是一样的所以直接上代码了: #include<stdio.h> int gcd(int y,int x) { return x?gcd(x,y%x):y; } int main() { int m,n,k,i; while(scanf("%d%d",&m,&n)!=EOF) { if(gcd(m,n)==1) printf("NO\n"); else { k=gcd(m,n); printf("%d ",n-(n-1)/k-1); i=0; while(i<n) { if(i%k) printf("%d ",i); ++i; } printf("\n"); } } } 10、A problem is easy 这道题目的本质实际上是要你找出一个数的因子的个数的。题目大致意思是说给你一数字n然后要你找出n可以有多少种表示为i*j+i+j的形式(0<i<=j),那么我们对这个问题稍作变换就可以看出,实际上是要找i*j+i+j+1=(i+1)*(j+1)=n+1,有多少整数解,那么问题也就转化为了将n+1分解为两个整数的乘积的形式。 对于这样的问题,最简单的思路就是拿1到n之间的数去一一试除了。当然可行,但是这里介绍一种更为快捷的办法。 基于数论的一个基本定理:我们知道任何一个大于1的整数n我们都可以写作这样的形式n=i=1kpiai 其中pi为n的素因子。 那么这个n的因子个数就是i=1k(ai+1),利用这个结论这个题目就可以很快算出来了。 代码如下(采用第一种思路): #include <stdio.h> #include <math.h> int main() { int i,j,k,l,m,n; scanf("%d",&m); while(m--) { scanf("%d",&n); n=n+1; l=sqrt(double(n)); for(i=2,k=0;i<=l;i++) { if(n%i==0) k++; } printf("%d\n",k); } } 采用第二种思路: #include <stdio.h> #include <math.h> #include <string.h> int prime[100006]; int visit[100006]; int pos=0; int getprime(int n) { memset(visit,0,sizeof(visit)); for(long long i=2;i<n;i++) { if(!visit[i]) for(long long j=i*i;j<n;j+=i) { visit[j]=1; } } for(int i=2;i<n;i++) { if(!visit[i]) prime[pos++]=i; } return pos; } int getfs(int n) { int ans=1; for(int i=0;i<pos && prime[i]*prime[i]<=n;i++) { int d=0; while(n%prime[i] == 0) { d++; n/=prime[i]; } ans*=(d+1); } if(n!=1) ans*=2; return ans; } int main() { getprime(100005); int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); printf("%d\n",(getfs(n+1)-2+1)/2); //printf("%d\n",(getfactionsum(n+1)-2+1)/2); } return 0; }
    展开阅读全文
    提示  咨信网温馨提示:
    1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
    2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
    3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
    4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
    5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
    6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

    开通VIP折扣优惠下载文档

    自信AI创作助手
    关于本文
    本文标题:ACM数论方面十道基础题目详解.docx
    链接地址:https://www.zixin.com.cn/doc/5960334.html
    页脚通栏广告

    Copyright ©2010-2026   All Rights Reserved  宁波自信网络信息技术有限公司 版权所有   |  客服电话:0574-28810668    微信客服:咨信网客服    投诉电话:18658249818   

    违法和不良信息举报邮箱:help@zixin.com.cn    文档合作和网站合作邮箱:fuwu@zixin.com.cn    意见反馈和侵权处理邮箱:1219186828@qq.com   | 证照中心

    12321jubao.png12321网络举报中心 电话:010-12321  jubao.png中国互联网举报中心 电话:12377   gongan.png浙公网安备33021202000488号  icp.png浙ICP备2021020529号-1 浙B2-20240490   


    关注我们 :微信公众号  抖音  微博  LOFTER               

    自信网络  |  ZixinNetwork