P05509. 寻找循环节

 

Description
f[1]=1

f[2]=1

f[3]=(f[2]+f[1])%mod

f[i]=(f[i-1]+f[i-2])%mod;

1<mod<=100000

输出循环节长度

某一个起向右进行到某一个止的一节序列出现,首尾衔接,这一节序列称为循环节

Format
Input
mod的值

Output
循环节长度

Samples
输入数据 1
2
输出数据 1
3

提示 1 1 0 1 1 0 所以循环节是3

 

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
map<pair<int,int>,int> w;
int mod,n,x,f[1000001];
int main()
{
    scanf("%d",&mod);
    f[1]=f[2]=1;
    w[make_pair(1,1)]=1;
//将数列的第1项,第2项进行打包,放入map,标为第1块
//后面将会把第2项,第3项进行打包,标为第2块。。。。。。。。。 for(int i=3;;i++) { f[i]=(f[i-1]+f[i-2])%mod; //算出数列第i项 x=w[make_pair(f[i-1],f[i])]; //准备对第(i-1,i)项进行查询,如果能查到的话,则说明前面出现过 //如果没查到,将则 (i-1,i)编号为第i-1块 if(x) { printf("%d",i-x-1); //从前曾被标记为第x块,现在在第i-1块又要出现 //于是循环节长度为i-x-1; return 0; } else w[make_pair(f[i-1],f[i])]=i-1; } }

  

 

#include<bits/stdc++.h>
using namespace std;
int mod,f[10000010];
struct node
{
int a,b; 
friend bool operator <(node xx,node yy)
{
	      
    if(xx.a==yy.a)
	     return xx.b<yy.b;
    else
	   	return xx.a<yy.a;
    
}//得判全不然map认为两个元素相等 

};
map<node,int> mp;
node temp;
int main() 
{
	cin>>mod;
	mp[{1,1}]=1;
	f[1]=1,f[2]=1;
	for(int i=3;; i++) 
	{
		f[i]=(f[i-1]+f[i-2])%mod;
		temp.a=f[i-1];
		temp.b=f[i];
		if(mp[temp]!=0) 
		{
			cout<<i-mp[temp]-1<<endl;
			return 0;
		}
		mp[temp]=i-1;
	}
}

  

 

有这样一个递推式

f(1) = 1

f(2) = 1

f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.

现在给你A,B,n,请求出f(n)的结果来

Format
Input
整个测试包括多组数据,当输入0 0 0代表结束

每个数据一行,给出数字A,B,n

1 <= A, B <= 1000, 1 <= n <= 100,000,000

Output
针对每个数据,一行输出其结果

Samples
输入数据 1
1 1 3
1 2 10
0 0 0
输出数据 1
2
5

 

 SOl

和上一个题差不多,a,b对问题的解决影响不大。

只要某对(f[i-1],f[i-2])从前曾经出现过,则出现循环节。

 

#include<bits/stdc++.h>
using namespace std;
map<pair<int,int>,int> w;
int mod,a,b,n,x,f[1000001],len;
int vis[111][111];

int main()
{
while (true)
{
	scanf("%d%d%d",&a,&b,&n);
	if (a == 0 && b == 0 && n == 0)
            break;
    memset(vis,0,sizeof(vis));   
    f[1]=f[2]=1;
    vis[1][1]=1;
    len=0;
    for(int i=3;i;i++) 
    {
    	
        f[i]=(a*f[i-1]+b*f[i-2])%7;
         //算出数列第i项 
        if (i==n)
    	{
    		cout<<f[i]<<endl;
    		break;
		}
        //x=w[make_pair(f[i-1],f[i])];
        x=vis[f[i-1]][f[i]];
        //准备对第(i-1,i)项进行查询,如果能查到的话,则说明前面出现过
		//如果没查到,将则 (i-1,i)编号为第i-1块 
        if(x)
        {
            len=i-x-1;
            //算出循环节 
            int temp=x-1;
            //算出循环节前面有多少个多余的数字 
            if (n<=temp)
            {
            	cout<<f[n]<<endl;
            	break;
			}
            int nn=(n-temp)%len;
            //看落在循环节哪个位置  
            if (nn==0)
            //如果为0的话,则在最后一个位置 
                nn=len;
            printf("%d\n",f[nn+temp]);
           // cout<<f[nn+temp]<<endl;
            //从前曾被标记为第x块,现在在第i-1块又要出现
			//于是循环节长度为i-x-1; 
            break;
        }
        else
           // w[make_pair(f[i-1],f[i])]=i-1;
           vis[f[i-1]][f[i]]=i-1;
    }
}
}

  

 

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
map<pair<int,int>,int> w;
int mod,a,b,n,x,f[1000001],len;
int vis[111][111];

int main()
{
//freopen("sequence1.in","r",stdin);
while (true)
{
	//cin>>a>>b>>n;
	scanf("%d%d%d",&a,&b,&n);
	if (a == 0 && b == 0 && n == 0)
            break;
    w.clear();    
    f[1]=f[2]=1;
    w[make_pair(1,1)]=1;
    len=0;
    for(int i=3;i;i++) 
    {
    	
        f[i]=(a*f[i-1]+b*f[i-2])%7;
         //算出数列第i项 
        if (i==n)
    	{
    		cout<<f[i]<<endl;
    		break;
		}
        x=w[make_pair(f[i-1],f[i])];
        //准备对第(i-1,i)项进行查询,如果能查到的话,则说明前面出现过
		//如果没查到,将则 (i-1,i)编号为第i-1块 
        if(x)
        {
            len=i-x-1;
            
            int temp=x-1;
            if (n<=temp)
            {
            	cout<<f[n]<<endl;
            	break;
			}
            int nn=(n-temp)%len;
            if (nn==0)
                nn=len;
            printf("%d\n",f[nn+temp]);
           // cout<<f[nn+temp]<<endl;
            //从前曾被标记为第x块,现在在第i-1块又要出现
			//于是循环节长度为i-x-1; 
            break;
        }
        else
            w[make_pair(f[i-1],f[i])]=i-1;
    }
}
}

  

 

Z2341. 寻找循环节
ID: 4107
传统题
1000ms
256MiB
尝试: 1
已通过: 1
难度: 10
上传者:

管理员 (root)
Description
有这样一个递推式 num[0]=1;

num[1]=2;

num[2]=4;

num[3]=6;

num[i]=(num[i-1]+num[i-3]+num[i-4])%2005;

现希望你求出num[n]来,N<=10^100000000000000000

这种题一看就知道递推式的值存在循环节,问题是循环节的长度是多少呢?

Format
Input

Output
输出一个数字,代表循环节

 

Sol

一个小坑在于,要记四个位置,这样才能确保循环节是对的。

#include<bits/stdc++.h>
using namespace std;
struct node
{
int a,b,c,d;
friend bool operator <(node xx,node yy)
{
	      
 //   return xx.a==yy.a?xx.b==yy.b?xx.c==yy.c?xx.d<yy.d:xx.c<yy.c:xx.b<yy.b:xx.a<yy.a;
    if(xx.a==yy.a)
		if(xx.b==yy.b)
			if(xx.c==yy.c)
				return xx.d<yy.d;
			else
		    	return xx.c<yy.c;
        else
		     return xx.b<yy.b;
    else
	   	return xx.a<yy.a;
    
	    }//得判全不然map认为两个元素相等 

};
map<node,int> mp;
int num[11111];
	node temp;
int main()
{
	num[0]=1;
	num[1]=2;
	num[2]=4;
	num[3]=6;
	for (int i=4;i<=11111;i++)
        {
		num[i]=(num[i-1]+num[i-3]+num[i-4])%2005;
		temp.a=num[i-4];
		temp.b=num[i-3];
		temp.c=num[i-2];
		temp.d=num[i-1];
		if (mp[temp])
		{
		
		    cout<<i-mp[temp]<<endl;
		    break;
	    }
	    mp[temp]=i;
	}
}

  

posted @ 2023-09-25 18:01  我微笑不代表我快乐  阅读(27)  评论(0编辑  收藏  举报