CCF有趣的数(快速幂,递推)

本文探讨了如何计算具有特定位数且只包含0,1,2,3的数字,同时满足数字顺序和最高位不为0条件的有趣数的个数,并提供了求解方法和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

  我们把一个数称为有趣的,当且仅当:
  1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
  2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。
  3. 最高位数字不为0。
  因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。
  请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。
输入格式
  输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000)。
输出格式
  输出只有一行,包括恰好n 位的整数中有趣的数的个数除以1000000007的余数。
样例输入
4
样例输出
3

题解

一开始看这题真的是毫无头绪,后来尝试从一些很简单的问题入手,发现这个数只能以2开头,以1或3结尾,情况以下子少了很多,于是看看能不能递推,思路如下:
- 设长度为n(n>=4)的有趣的数个数为a[n]
- 考察a[n+1],
- 若这个数以1结尾
- 若前n位有0123,该情况数是a[n]
- 若前n位没有1,设第一个3出现的位数是k(1≤k≤n-1,从左往右从1开始),该种情况方法数为2k1×2nk11=2n21,于是总的方法数为(n-1)(2n21)
- 若这个数以3结尾
- 若前n位有0123,该情况数是a[n]
- 若前n位没有3,情况略有不同,设第一个1出现的位数是k(2≤k≤n-1),该种情况方法数为(2k11)×2nk1=2n12nk1,于是总的方法数为n1k=2(2n12nk1)=(n3)×2n2+1
- 综上,a[n+1]=2a[n]+(n-2)*2n1-n+2
- 但是直接这么算,n稍微大一点就会溢出,因此要随时取模

/*a[n+1]=2a[n]+(n-2)2^(n-1)-n+2*/
#include<stdio.h>
#define m 1000000007
long long Pow(int n)/*计2^n mod m*/
{
    if (n==1)
        return 2;
    long long half;
    half=Pow(n/2);
    if ((n&1)==0)
        return (half*half)%m;
    else
        return (((half*half)%m)*2)%m;
}
int main(void)
{
    long long a=3;
    int i,n;
    scanf("%d",&n);
    for (i=4;i<n;i++)
        a=(a*2+(i-2)*Pow(i-1)-i+2)%m;/*可以保证在取余之前不会溢出,如果是int的话,(i-2)*Pow(i-1)可能会溢出*/
    printf("%lld",a);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值