hdu 1005 Number Sequence(找循环)

这个题并不是什么难题,写这篇题解的原因是现在CSDN上的大部分%50,%49,%48的题解原理不太对,hdu此题的测试数据比较水,经过探索我发现了网上很多ac代码并过不了一些特殊的数据。因此,在这里做个我认为最正确的题解。

首先讲述一下抽屉原理在此题的应用:

很显然,根据题意,f[]数组是一个由0-6七个数字组成的数组,我们现在只考虑 f[i] 和 f[i+1] 两个相邻元素,我们现在把这对数字叫做相邻。那么让我们来考虑一下这些相邻配对可能出现的情况。可能是0,0、0,1、0,2、……很显然,它们只可能是0-6的排列,这一对数字只可能有49种情况。由于没有第50种出现的可能,在f数组前51个数中(前51个数有50组相邻配对),一定会出现两组一样的相邻配对。又因为每个元素只与它的前面两个元素有关系,因此必定在前51个数种会产生循环。

然而,与网上大多数题解所认为的循环节(也就是一个循环单位)长度一定是49的因数相违背的是,当a=2,b=7时,f的情况是  1,1,2,4,1,2,4,1,2,4……,在这种情况下循环节为3,且循环节并没有包括开头的 1,1 ,因此当输出 n=52时,它们得到的输出往往是 2,并不是正确答案 4。这一点由于oj数据太水让他们ac了。

针对这种特殊情况,我们可以得到以下结论:

1、循环节不一定包括开头所给的初始值 1,1

2、循环节的长度我无法预测有什么规律

3、开始循环的起点我也无法预测

那么这个问题就转化成:我需要一边计算f的值,一边寻找是否已出现循环点(也就是出现了两对相同的相邻配对),我需要找出循环的起点,循环节的长度。

由于我们已经知道了前51个数肯定会出现循环,那我们暴力就行了,时间肯定够的不要虚,最后时间复杂度最坏是O(50*50),也就是O(1)嘛,不虚不虚,每计算出一个新的 f[i],我就向前搜一下,有没有出现过 f[i] 与 f[i-1] 组成的循环配对。

上代码

#include<iostream>
#include<vector>
#include<stdio.h>
#include<cmath>
#include<string>
#include<string.h>
#include<limits>
#include<limits.h>
#include<algorithm>
#include<queue>
#include<set>
#include<bits/stdc++.h>
#include<map>
using namespace std;
int f[100];
int length,st;//循环节长度和循环开始的标记
bool finda(int n){
    int a=f[n-1],b=f[n];
    for(int i=1;i<n-1;i++){
        if(f[i]==a&&f[i+1]==b){
            st=i;
            length=n-1-i;
            return true;
        }
    }
    return false;
}

int main(){
    int a,b,n;
    while(1){
        cin>>a>>b>>n;
        if(a==0)break;
        f[1]=1;f[2]=1;
        for(int i=3;i<100;i++){
            f[i]=(a*f[i-1]+b*f[i-2])%7;
            if(finda(i))break;
        }
        if(n<st)cout<<f[n]<<endl;
        else cout<<f[(n-st)%length+st]<<endl;

    }


}

另附一些能ac代码确不能通过的数据,只有2 7 52是我自己找到的,剩下的是贴的hdu discuss 区的http://acm.hdu.edu.cn/discuss/problem/post/reply.php?postid=34360&messageid=6&deep=2

2 7 52
247 602 35363857
376 392 9671521
759 623 18545473
53 399 46626337
316 880 10470347
0 0 0
4
4
3
5
2
3
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值