一个高中的信息学竞赛的题

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 打赏 收藏 转发到动态 举报
写回复
用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

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧