201312-4有趣的数

一、题目

问题描述

试题编号:201312-4
试题名称:有趣的数
时间限制:1.0s
内存限制:256.0MB
问题描述:

问题描述

  我们把一个数称为有趣的,当且仅当:
  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

二、分析

这个题很考察动态规划的思想,非常考察,我完全不会,因为我脑子中不能时刻保持动态规划的想法,敏锐地看出状态转换,以及如何确定那些状态是什么。一切的思考都从穷举开始的,首先,我的想法是我大不了把所有的1000位数字全部列举出来,然后一一判断满不满足上边3个条件,这一点是很容易做到的,而且是很直观的,但是,显然时间复杂度很高,首先这样的判断要有4的1000次方次,以及爆了,其次,条件1是1000的,条件2是1000的平方的,条件3是常数的。然后我就想怎么搞,然后就不会了,就没有然后了。这个题目值得深究,从而找到一种由我的这种懵逼状态到正确状态的一个简单路径,平滑过渡到正确的会做题的状态。这个题我做了好几个月,之前第一遍一看,萌萌的不会,看了答案忘了,然后几个月后一看不会画出来个ABCD的下一个的相邻图,然后没法分析了,不会,看了答案,发现要那么做,于是想到一个问题,是不是可以从我的ABCD图变换乘那个什么状态图呢,感觉应该有这种变换方法把,两者的区别在于我那个活动在点上,指向这个点就是加上这个,而转态图不是,它是活动在边上的,就是这个线代表了后边加上某个A,然后它的节点是自己抽象出来的状态,这种抽象我难以想象,为什么是用过哪些点的这种状态呢?其它状态就不行么?ABCD图的边不代表什么,全是相同的,意思是加上这种或者后边那个,而状态转换图中的边是不同的操作,比如A->AB就是加上B,而A->AC就是加上C,这些边是不一样的操作,不同的含义。

那么我是如何做出来的呢?以上提交其实都是我在看了其他人的答案之后写的,第一次交错了格式,第二次我没有引用头文件iostram好像是,第三次初始化的值不对,因为我想着从4开始进行迭代动态规划,结果我的写的3,1,1,1,1,1。第四次,我把整个加乘都改了,我改成了加前一个的圈圈乘的倍数,当然是错的啊,然后我就改回去了,第五次是写的初值对了,1,7,3,5,9,3,但是我的状态转换图我在之前改bug时稍微胡乱改了一下,然后3的地方要乘以2,我之前改bug居然给删了2,就错了,我以为是我%1007导致的,于是删除%又提交一次,还是10分,然后我就检查啊,最后也没检查出来,还是看了答案才发现人家是从1就开始的,我还很傻的自己算4的东西,1,7,3,5,9,3,那啥我就按照我的草稿图算了一次,发现5是4,怀疑自己穷举4的穷举错了,然后看了看没错啊,嗯,肯定是我的草稿图错了,然后,果然,本来有两个线,我不知什么时候删去了一个线,然后就错了。

中间我怎么检查的呢,就是运行输入个5看看啥样,运行输入个1000看看啥样,改改代码,看看1000的变没变,100的啥的。

现在我依然只能靠短期记忆做这个题,以后看看能不能让我脑子自动动态规划吧。

对了这个题有应用的现实场景,比如n个节点,然后DDL是某个长度,然后拓扑给出,问DDL是多长可以遍历所有节点的路径有多少条,然后我们就能算出概率,那个DDL固定长度时,遍历所有节点的概率,然后就能设置最佳的DDL使得遍历节点概率最大化,当然,这里的场景是可以自己发给自己,即使不可以自己发给自己的话页应该是可以用动态规划来做出来的吧,大不了加上限制不能重复出现两个相邻的相同的字母节点罢了,而这一点可以通过修改动态规划的式子做到吧?好像是不能的,因为我们的这个状态图并不关心末尾一位是什么东西,只关心其这个长度的状态可能有多少,这样,末尾一位就没有记忆肯定是会损失的,只有添加不同字母时是确定可以这么做的,而状态图中的环就很难分析到底有多少个了,这个是这个问题的难点,这个问题其实还可以拓展开去,比如不能发过去又发回来,这就是一种路由机制了,然后限制就成了即不能AA,也不能ABA这个样子,然后分析难点依然是那个状态转换图中的环,我累了,就不再深究了,反正这个题我不会,我做题的时候基本上都是在想这些奇怪的东西,根本就浪费很多时间,然后题目就不会做了,然后就自己很差劲的样子。然后,还有一个没解决的问题是为什么能够每次算了后都%1007呢,这么做的原理是什么,尽管我也感觉这么做是对的,但是我的感觉一般都不靠谱所以就不敢相信自己的感觉,然后就想把自己会的所有东西全部托管给自己感觉来做,教会它,把感觉正确和事实正确联系起来,然后凡事靠感觉做题就行了。

三、代码

#include <stdio.h>
#include <iostream>
using namespace std;
long long states[1001][6];
//0 2
//1 20
//2 23
//3 201
//4 203 230
//5 0123
int main(){
int n;
cin>>n;
states[4][5]=3;
states[4][4]=9;
states[4][3]=5;
states[4][2]=3;
states[4][1]=7;
states[4][0]=1;
int i,j;
for(i=5;i<=n;i++){
states[i][0]=1;
states[i][1]=(2*states[i-1][1]+1)%1000000007;
states[i][2]=(states[i-1][2]+1)%1000000007;
states[i][3]=(2*states[i-1][3]+states[i-1][1])%1000000007;
states[i][4]=(2*states[i-1][4]+states[i-1][1]+states[i-1][2])%1000000007;
states[i][5]=(2*states[i-1][5]+states[i-1][3]+states[i-1][4])%1000000007;
}
cout<<states[n][5];
return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值