社区
C语言
帖子详情
一个高中的信息学竞赛的题
chenzhiwei021
2007-09-15 10:36:51
#include <stdio.h>
long g(long k) {
if (k <= 1) return k;
return (2002 * g(k - 1) + 2003 * g(k - 2)) % 2005;
}
int main() {
long n;
scanf("%ld", &n);
printf("%ld\n", g(n));
return 0;
}
输入:2005
输出:
...全文
669
18
打赏
收藏
一个高中的信息学竞赛的题
#include long g(long k) { if (k <= 1) return k; return (2002 * g(k - 1) + 2003 * g(k - 2)) % 2005; } int main() { long n; scanf("%ld", &n); printf("%ld\n", g(n)); return 0; } 输入:2005 输出:
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
18 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
this_
2007-10-06
打赏
举报
回复
NOIP 复赛 回答程序结果题第4题~极其无聊
找规律变迭代~
无聊的NOIP
shorring
2007-10-06
打赏
举报
回复
这个其实就是中学中最常见的数列通项公式
conectMouse
2007-10-03
打赏
举报
回复
这是数学题..
deng2000
2007-10-03
打赏
举报
回复
看来楼主想得到一个分析解.让我们试着用一点初等数论的知识解决此题.
首先,让我们试着求出g(k)的通项公式.
令数列f(k)满足
f(0)=0, f(1)=1, f(k)=2002*f(k-1) + 2003*f(k-2)
则有 g(k) = f(k) % 2005
(注意同余式的基本性质: 若M=m(mod 25), N=n(mod 2005), 则对任意整数a,b,有 a*M+b*N = a*m+b*n (mod 2005) )
f(k)是个齐次递归数列,其通项公式(如12楼zhulinpptor指出的)由特征方程
x^2-2002x-2003=0 决定
因为方程有两个根 x1=2003, x2=-1, f(k)的通项公式为
f(k) = m*2003^k + n*(-1)^k
其中m,n为待定系数
由f(0)=1, f(1)=1 不难得出 m=1/2004 n=-1/2004
故有
f(k) = 1/2004*2003^k - 1/2004*(-1)^k
= 1/2004 * ((2003)^k - (-1)^k)
从而
g(k) = f(k) % 2005
= (1/2004 * ((2003)^k - (-1)^k)) % 2005
= (-1 * ( (-2)^k - (-1)^k)) % 2005 // 注意 1/2004=1/-1=-1 (mod 2005), 2003=-2 (mod 2005)
= (-1 * (-1)^k * (2^k - 1)) % 2005
即 g(k) = ((-1)^(k+1) * (2^k - 1)) % 2005
上式就是g(k)的通项公式
因此, g(2005) = ((-1)^2006 * (2^2005 - 1)) % 2005
= (2^2005 - 1) % 2005
现在的问题是,如何计算2^2005这样大的一个数除以2005的余数? 如果我们能找到某个数n,使得
2^n = 1 (mod 2005), 那我们只需计算2的(2005%n)次幂就行了,大大减小计算量.
学过数论的同学马上就会想到Euler定理
2005只有两个素因子 5, 401, 因此它的Euler数是
(5-1)*(401-1) = 1600
故有 2^1600 = 1 (mod 2005)
简单的计算我们还可得到比上式更该的结果,实际上,有
2^200 = 1 (mod 2005)
有了上式这个工具,g(2005)就呼之欲出了:
g(2005) = (2^2005 -1) % 2005
= (2^2000*2^5 -1 ) % 2005
= (2^5 -1 ) % 2005
= (32 - 1) % 2005
= 31
chenzhiwei021
2007-10-02
打赏
举报
回复
我想说的是这个是一个高中信息学竞赛题目,并且是笔试,对数学的要求瞒高的!很显然是一个周期的函数。
chen_de_sheng
2007-09-17
打赏
举报
回复
我说句废话啊,改成迭代就好的。。。
lovewhzlq
2007-09-17
打赏
举报
回复
g(k)=(2002*g(k-1)+2003*g(k-2))%2005;
g(0)=0
g(1)=1
g(2)=(2002*1+2003*0)%2005
=2002%2005+0
g(3)=[2002*((2002*1+2003*0)%2005)+2003*1%2005]%2005
=[2002*2005+2002+2003]%2005
=[2003+2002*1]%2005
g(4)={2002*[2002*((2002*1+2003*0)%2005)+2003*1]%2005+2003*(2002*1+2003*0)%2005}%2005
=[2002*2005+2002*2005+2002+2003+2003+2003*2005+2002]%2005
=[2003*2005*2+2002*2005+2003+2002*2]%2005
=[2003+2002*2]%2005
g(n)=2003*2+2002*3+2001
...
g(2005)= (2002*g(2004)+2003*g(2003))%2005
= (2002*[(2002*g(2003)+2003*g(2002))%2005]+2003*[(2002*g(2002)+2003*g(2001))%2005])%2005
=...
=
因为这个递归程序是按这种方式进行递推,它要先计算出(2002*[(2002*g(2003)+2003*g(2002))%2005]+2003*[(2002*g(2002)+2003*g(2001))%2005])之后才会模2005,而long型的精度已经不够它计算了!!!所以用一个太大的数去递归计算机已无法处理!!!
pptor
2007-09-17
打赏
举报
回复
可以转换成
g(0)=0
g(1)=1
g(n)=2002g(n-1)+2003g(n-2) (n>1) ..........[1]
求g(2005)%2005
对于[1] 可以求到通项公式:
求解如下,
x^2-2002x-2003=0
得到 x1=20003 x2=-1
所以 通项为 (2005-2)^(n-k0) +(-1)^(n-k0)
再根据g(0),g(1)的值应当可以得到 k0的值得
到这时 问题差不多已经解决了
GodCupid
2007-09-16
打赏
举报
回复
不是让大家来改原题,只是有没有人能知道技巧!!
这是什么话,人家给程序都改了,那是肯定知道怎么回事了
#include <stdio.h>
int main() {
long n,a0,a1,i,r;
a0=0;
a1=1;
scanf("%ld", &n);
for(i=2;i<=n;i++){
r=(a1*2002+a0*2003)%2005;
a0=a1;
a1=r;
}
printf("%ld\n",r);
getch();
return 0;
}
迭代得出:(<0.05s)
31
风清扬大哥的程序令小弟很佩服
makewater
2007-09-16
打赏
举报
回复
还是别浪费脑子在这种题目上了
实际应用上 基本上不会遇到
chenzhiwei021
2007-09-16
打赏
举报
回复
不是让大家来改原题,只是有没有人能知道技巧!!
CQZE
2007-09-15
打赏
举报
回复
靠,不用计算机这个怎么算.
&n 就这个就可以秒杀
laiwusheng
2007-09-15
打赏
举报
回复
#include <stdio.h>
int main() {
long n,a0,a1,i,r;
a0=0;
a1=1;
scanf("%ld", &n);
for(i=2;i<=n;i++){
r=(a1*2002+a0*2003)%2005;
a0=a1;
a1=r;
}
printf("%ld\n",r);
getch();
return 0;
}
迭代得出:(<0.05s)
31
tdcr5
2007-09-15
打赏
举报
回复
楼上正解
这个第归效率太低,改迭代比较好
chenzhiwei021
2007-09-15
打赏
举报
回复
答案是31,很明确不可能去手工递推,肯定有什么技巧的。
就是用计算机去做,别说是2005,就是100都要算很长的时间。
WizardOz
2007-09-15
打赏
举报
回复
递归到一定程度是计算机算起来都很吃力的,既然都知道它的原理了,还让人手工算,实在是很无聊。
laiwusheng
2007-09-15
打赏
举报
回复
g(k)=(2002*g(k-1)+2003*g(k-2))%2005;
g(0)=0
g(1)=1
g(2)=(2002*1+2003*0)%2005
=2002%2005+0
g(3)=[2002*((2002*1+2003*0)%2005)+2003*1%2005]%2005
=[2002*2005+2002+2003]%2005
=[2003+2002*1]%2005
g(4)={2002*[2002*((2002*1+2003*0)%2005)+2003*1]%2005+2003*(2002*1+2003*0)%2005}%2005
=[2002*2005+2002*2005+2002+2003+2003+2003*2005+2002]%2005
=[2003*2005*2+2002*2005+2003+2002*2]%2005
=[2003+2002*2]%2005
g(n)=2003*2+2002*3+2001
...
g(2005)= (2002*g(2004)+2003*g(2003))%2005
= (2002*[(2002*g(2003)+2003*g(2002))%2005]+2003*[(2002*g(2002)+2003*g(2001))%2005])%2005
=...
=
不推了。。。
wangorg
2007-09-15
打赏
举报
回复
1
全国奥林匹克
信息学
竞赛
---noip资料;试
题
高中
信息技术
竞赛
资料 奥林匹克信息技术
竞赛
试
题
信息学
奥赛试卷
一份
信息学
竞赛
的试卷,适用于NOIP
竞赛
《
信息学
竞赛
-C/C++入门》 C++语言
尹成老师带你步入C++语言基础的殿堂,讲课生动风趣、深入浅出,全套视频内容充实,整个教程以C++语言为核心,完整精彩的演练了C++语言操作流程以及各种精彩的小项目等,提高
竞赛
能力,非常适合同学们学习!
信息学
奥赛第一届~第八届小学、初中、
高中
组
题
目+测试数据
信息学
奥赛第一届~第八届小学、初中、
高中
组
题
目+测试数据
信息学
奥赛第一届~第八届小学、初中、
高中
组
题
目+测试数据
NOIP2013 提高组初赛笔试试
题
C++
最新2013年全国中学生
信息学
奥林匹克
竞赛
高中
组
竞赛
初赛笔试试
题
,文档清晰
C语言
69,371
社区成员
243,082
社区内容
发帖
与我相关
我的任务
C语言
C语言相关问题讨论
复制链接
扫一扫
分享
社区描述
C语言相关问题讨论
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章