CCF 201312-4 有趣的数


分析:
题目是一个有限制的数字序列问题。
题目的限制条件可以大体上分为:

  • 给定数字的先后顺序限制
    • 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前
    • 最高位数字不为0
  • 数字出现次数
    • 数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次

本题中我们难以将数字的先后顺序和个数的限制同时简单实现.
我们只好分开实现。
我们优先实现顺序限制(条件更多方便具体化实现)
没有数字都出现至少一次的限制时,就可以有多具体情况(我们称这些数字为“前有趣数”):

  1. 只有2
  2. 只有2,0
  3. 只有2,3
  4. 只有2,0,3
  5. 只有2,0,1
  6. 有2,3,0,1

显然情况6就是我们要求的,不用数字出现限制去筛选。此时状态转移就可以很容易递推求各种情况的“前有趣数”设 d p [ i ] [ j ] dp[i][j] dp[i][j]为长度为就 i i i j j j号序列。
(我们接下来在序列中将"+"作为连接操作)

  1. 0号序列(情况1) 2...22 ⇐ 2...2 + 2 2...22\Leftarrow2...2+2 2...222...2+2,即 d p [ i ] [ 0 ] = d p [ i − 1 ] [ 0 ] \\dp[i][0] = dp[i-1][0] dp[i][0]=dp[i1][0]

  2. 1号序列(情况2) 2..0..2 ⇐ 2..0.. + 2 或 2..0..0 ⇐ 2..0.. + 0 或 2...20 ⇐ 2...2 + 0 2..0..2\Leftarrow2..0..+2\\或2..0..0\Leftarrow2..0..+0\\或2...20\Leftarrow2...2+0 2..0..22..0..+22..0..02..0..+02...202...2+0,即 d p [ i ] [ 1 ] = ( d p [ i − 1 ] [ 1 ] ∗ 2 + d p [ i − 1 ] [ 0 ] ) \\dp[i][1] = (dp[i-1][1]*2+dp[i-1][0]) dp[i][1]=(dp[i1][1]2+dp[i1][0])
    同理可以得到

  3. d p [ i ] [ 2 ] = ( d p [ i − 1 ] [ 0 ] + d p [ i − 1 ] [ 2 ] ) dp[i][2] = (dp[i-1][0]+dp[i-1][2]) dp[i][2]=(dp[i1][0]+dp[i1][2])

  4. d p [ i ] [ 3 ] = ( d p [ i − 1 ] [ 1 ] + d p [ i − 1 ] [ 3 ] ) + ( d p [ i − 1 ] [ 2 ] + d p [ i − 1 ] [ 3 ] ) dp[i][3] = (dp[i-1][1]+dp[i-1][3])+(dp[i-1][2]+dp[i-1][3]) dp[i][3]=(dp[i1][1]+dp[i1][3])+(dp[i1][2]+dp[i1][3])

  5. d p [ i ] [ 4 ] = ( ( d p [ i − 1 ] [ 1 ] + d p [ i − 1 ] [ 4 ] ) + d p [ i − 1 ] [ 4 ] ) dp[i][4] = ((dp[i-1][1]+dp[i-1][4])+dp[i-1][4]) dp[i][4]=((dp[i1][1]+dp[i1][4])+dp[i1][4])

  6. d p [ i ] [ 5 ] = ( d p [ i − 1 ] [ 3 ] + d p [ i − 1 ] [ 5 ] ) + ( d p [ i − 1 ] [ 4 ] + d p [ i − 1 ] [ 5 ] ) dp[i][5] = (dp[i-1][3]+dp[i-1][5])+(dp[i-1][4]+dp[i-1][5]) dp[i][5]=(dp[i1][3]+dp[i1][5])+(dp[i1][4]+dp[i1][5])

#include<iostream>
#include<cstdio>
using namespace std;
const int Mod = 1000000007;
int dp[1005][6],N; 
/*
0;仅有2
1:有2,0
2: 有2,3
3:有2,0,3
4:有2,0,1
5:有2,0,1,3 
*/
int main(){
	cin >> N;
	for(int i = 0;i < 6;i++)dp[0][i] = 0;
	dp[1][0] = 1;
	for(int i = 2;i <= N;i++){
		dp[i][0] = dp[i-1][0];
		dp[i][1] = (dp[i-1][1]*2%Mod+dp[i-1][0])%Mod;
		dp[i][2] = (dp[i-1][0]+dp[i-1][2])%Mod;
		dp[i][3] = ((dp[i-1][1]+dp[i-1][3])%Mod+(dp[i-1][2]+dp[i-1][3])%Mod)%Mod;
		dp[i][4] = ((dp[i-1][1]+dp[i-1][4])%Mod+dp[i-1][4])%Mod;
		dp[i][5] = ((dp[i-1][3]+dp[i-1][5])%Mod+(dp[i-1][4]+dp[i-1][5])%Mod)%Mod;
	}
	cout << dp[N][5]<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值