题目大意:给出A,B,N三个参数根据公式f(n)=(A*f(n-1)+B*f(n-2))mod7计算f(n)?其中f(1)=1,f(2)=1,0<N<=100000000,0<A,B<1000.
算法思想:从题目中可以看出N很大,如果用一般方法肯定会超时,同时若设置规模为N的一维数组记录f[n]肯定会超内存,所以基于以上考虑采用滚动数组来解决内存问题,同时通过找出递推公式的规律来简化问题的规模。此处主要用到一些模数的性质(1)(a*b)%m=(a%m*b%m)%m (2) (a+b)%m=(a%m+b%m)%m;利用这两条性质可以将递推公式化简如下:f(n)=(A%7*f(n-1)+B%7*f(n-2)]%7,接下来对此公式进行分析:(引用http://acm.hdu.edu.cn/discuss/problem/post/reply.php?postid=10343&messageid=2&deep=1)
首先我记f[n]=g(f[n-1],f[n-2]) 由于题目中脑残的%7 很显然这里对f[n]的值域A,有|A|<=48,其中由于初始值为1,1 显然要排除掉g(0,0)(不要问为什么,很显然。。) 接下来我们得到一个显而易见的结论,即f[n]必存在周期,且周期小于等于48 我用一个程序测试了一下,可能的周期解为 1,2,3,4,6,8,12,14,16,21,24,42,48 不要问为什么 事实上对于1,2,3,4,6,8,12,16,24,48 你们懂的 所以测试数据漏掉了什么情况?即14,21,42的情况 正确的解法应该算出前96个解,然后找到最小正周期 利用周期函数的特性给出答案 而不是针对测试数据的漏洞用脑残的方法解答 最后吐槽下用循环数组竟然不能暴力解掉。。 ---------------------------------------------------------------------------------- 首先我不知道为什么说要排除掉g(0,0) 我没看到很显然的东西 题目中既然没有说a b不能是7的倍数,那么输入a=7 b= 7就是合法的,得到的序列就是 1 1 0 ...0 以后就都是g(0, 0) 周期小于等于48 这个我没算过,但是既然每个值都是在0-6之间,那么周期在49以内就是一定的,而出现0 0后,又一定是0 0循环下去,那么周期最大是48也是可以理解的 但是为什么要算96个解呢? 49个解已经足够了,出现第一个相同点,后面一定是相同的, 而最大周期是48,当算到49的时候,至少有一个是循环的了,这已经足够了代码如下:
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
int f[3];
int dp(int a,int b,int n)
{
f[1]=1;
f[2]=1;
for(int i=3;i<=n%48;i++){
f[0]=f[1];
f[1]=f[2];
f[2]=(a*f[1]+b*f[0])%7;
}
return f[2];
}
int main(){
int a,b,n;
while(cin>>a>>b>>n&&a!=0&&b!=0&&n!=0){
cout<<dp(a,b,n)<<endl;
}
return 0;
}