• 题解 P4910 【帕秋莉的手环】


    对于这道题,我第一眼竟然是去看标签,然后跟着标签推思路
    题目很长,我在这就不赘述了。

    简单理解,就是给定一个 n,条件是长度为n的一串 01 (我们将木属性定为 0 ,金属性定为 1) 数列中不能有连续的两个 0,因为又是环,所以当数列的首位中有一个为 0 的话,另一个就不能为 0,求满足条件的长度为 n 的数列有多少种,答案对 1000000007 取模。

    说实话,我没看懂样例解释。 但并不妨碍我们去分析题目。

    当 n = 1 时 只有 1 这一种情况。

    当 n = 2 时 有 10 11 01 三种情况。

    现在,我们以 n = 1 和 n = 2 为基础,往后进行推测。

    当 n = 3 时

    当首位为 0 时,只有 011 一种情况。
    当首位为 1 时 有 111 101 110 三种情况。
    

    共四种情况

    当 n = 4 时

    当前两位为 10 时 后面可接 10 11 两种情况。
    当前两位为 11 时 后面可接 10 11 01 三种情况。
    当前两位为 01 时 后面可接 11 01 两种情况。
    

    共七种情况

    同理,当 n = 5 时,对首位和倒数第二位进行分类讨论

    当首位为 1 时
    	倒数第二位为 1 时 可接 1 0 。
    	倒数第二位为 0 时 可接 1 。
    当首位为 0 时
    	倒数第二位为 1 时 可接 1 。
    	倒数第二位为 0 时 可接 1 。
    

    再根据 n = 4 时的七种情况,可推出共有十一种情况

    现在我们再回头看,可以发现

    n [ 3 ] = n [ 2 ] + n [ 1 ]

    n [ 4 ] = n [ 3 ] + n [ 2 ]

    n [ 5 ] = n [ 4 ] + n [ 3 ]

    这不就是斐波那契数列嘛

    既然我们已经推出了这道题的核心思想,那么剩下的就很好解决了。

    但要注意 1 ≤ n ≤ 10^18 ,正常的递推肯定会超时,所以我们需要用矩阵快速幂来加速,如果还不知道的建议先去了解这道题 斐波那契数列

    附上代码

    #include<bits/stdc++.h>
    #define ll long long
    const int mod=1e9+7;
    using namespace std;
    struct miku{
      ll a[3][3];
      miku()
      {
      	memset(a,0,sizeof(a));
      }
    }MIKU,IA;//矩阵
    miku operator *(const miku &x,const miku &y)//重载运算符
    {
      miku z;
      for(int k=1;k<=2;k++)
      	for(int i=1;i<=2;i++)
      		for(int j=1;j<=2;j++)
      			z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
      return z;
    }
    void Vocaloid()
    {
      MIKU.a[1][1]=3,MIKU.a[1][2]=1;
      MIKU.a[2][1]=0,MIKU.a[2][2]=0;
      IA.a[1][1]=1,IA.a[1][2]=1,IA.a[2][1]=1,IA.a[2][2]=0;
    }//初始矩阵的赋值
    ll read()//快读
    {
      long long x=0,flag=1;char ch=getchar();
      while(!isdigit(ch)) {if(ch=='-') flag=-1;ch=getchar();}
      while(isdigit(ch)) {x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
      return x*flag;
    }
    int T;
    ll n;
    int main()
    {
      scanf("%d",&T);
      while(T--)
      {
      	n=read();
      	Vocaloid();
      	miku ans=MIKU;
      	if(n<=2)//特判一下,当 n ≤ 2 时,直接输出
      	{
      		if(n==1) puts("1");
      		else if(n==2) puts("3");
      		continue ;	
      	} 
      	n-=2;
      	do
      	{
      		if(n&1) ans=ans*IA;
      		IA=IA*IA;
      		n>>=1;
      	}while(n);
      	printf("%d
    ",ans.a[1][1]%mod);
      }
      return 0;
    }
    

    PS:

    其实此题和这道题和像 单词

    如果有什么问题可以在评论区提出,我会尽己所能去回答的 (毕竟我也才学信息没多久)

    这是本人的第一篇题解,如果有什么问题还请管理员大大提出,我会加以改正 QAQ 。

  • 相关阅读:
    【SpringBoot】04.SpringBoot整合Filter的两种方式
    【SpringBoot】03.SpringBoot整合Servlet的两种方式
    【SpringBoot】02.编写HelloWorld
    【SpringBoot】01.创建Springboot项目及启动器
    Nginx——安装Nginx(二)
    Nginx——Nginx概述(一)
    与、或、异或的运算
    设计模式——单例模式
    MYSQL在当前日期的基础上加上N(年月日分秒)
    阿里云简单的HTTPS配置
  • 原文地址:https://www.cnblogs.com/MIKU5201314/p/13525389.html
Copyright © 2020-2023  润新知