CCF201312-4 有趣的数 不会DP只会枚举
来源:互联网 发布:ubuntu下安装jdk9 编辑:程序博客网 时间:2024/03/28 23:09
========================================= 原题 ============================================
问题描述
我们把一个数称为有趣的,当且仅当:
1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。
3. 最高位数字不为0。
因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。
请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。
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
========================================= 思路 ============================================
听闻网上大牛动不动就数位DP...宝宝做不到啊 =、=
看到这个题想了半天递推公式,感觉不是很麻烦但就是不想推...然后就有了下面这种乱七八糟的解法:
首先看到题发现了两个问题:
1、0/1和2/3之间没有特殊联系
2、数字首位必须是2
先解释下首位2的问题:如题0/2必须在1/3前面,0/1/2/3必须出现至少一次,所以首位只能是0/2(否则总有一个无法出现),但0不能做首位,所以首位必定是2。
然后就是最关键的一点——首个1和首个3的位置问题。
关于一个n位有趣数的可能情况如果直接写可能非常复杂,即便按照递推式也很麻烦,但只关注首个1/3就简单多了:1出现的比3早、3出现的比1早。
假设首个1出现在第 i 位,首个3出现在第 j 位。
① 1出现的比3早(i < j)
由假设可知,在0~i 位之间没有1/3只有0/2,在 i ~ j 之间只有1/2,在 j ~ n 之间只有1/3,出去固定位置(0、i、j)外每个位置都有两种可能,共2^(n-3)种可能。其中存在不符合要求的可能性——全是2没有0——i 之前没有0,i之后不影响。所以减去错误可能2^(n-i-1),所得结果即为当前i、j情况下结果总数。
② 3出现的比1早(i > j)
情况其实和前一种类似,只是考虑错误情况时候的计算变成了2^(n-i)种可能了(3在前面)。
知道了每种情况下的错误计算,还需要注意一下总数的问题:这里总结果数取的是【1/3可能数 × 0/2可能数 - 错误数】,其中1/3可能因为3的位置出现区别(3可以出现在第2位但1不可以,否则0无法出现)。
下面是AC代码(附带两个防溢出的函数):
#define MOD 1000000007#include<iostream>using namespace std;int getnum(int n){int k = 1;for (int i = 1; i <= n; i++){k *= 2;k %= MOD;}return k;}int mul(int a, int b){int k = 0;for (int i = 0; i < b; i++){k += a;k %= MOD;}return k;}int main(){int n;cin >> n;long long n13 = ((n - 2)*(n - 3) + n - 2) % MOD;long long n02 = getnum(n-3);long long ans = (n13*n02) % MOD;// 这里直接把3出现的可能乘进去了// 因为2必定出现所以不用单独考虑3的错误// 首个1出现在首个3之前for (int i = 3; i < n; i++){if (n - i - 1 >= 0){int wr = mul(getnum(n - i - 1), n - i);ans -= wr;// 分步取模可能出现计算后负数while (ans <= 0){ans += MOD;}}}// 首个3出现在首个1之前for (int i = 3; i <= n; i++){if (n - i >= 0){int wr = mul(getnum(n - i), i - 2);ans -= wr;while (ans <= 0){ans += MOD;}}}cout << ans%MOD << endl;return 0;}
阅读全文
2 0
- CCF201312-4 有趣的数 不会DP只会枚举
- CCF201312-4有趣的数
- CCF201312-4 有趣的数
- ccf201312-4有趣的数,递推
- CCF201312-4 有趣的数(100分)
- CCF 有趣的数 【DP】
- dp-ccf-有趣的数
- ccf 有趣的数 DP
- CCF 201312-4 有趣的数 (数位DP)
- CCF 201312-4 有趣的数(数位DP)
- CCF习题 201312-4有趣的数 (DP)
- 第一次CCF-4-有趣的数(DP)
- CCF201312-1 出现次数最多的数
- CCF201312-1-出现次数最多的数
- CCF201312(1)出现次数最多的数
- 我只会使用FreeTextBox编辑器,不会其他的
- DP求解有趣的数问题
- ccf 有趣的数(数位dp)
- Hadoop安装
- 用html如何把页面分割成多个文件,由多个文件拼接而成?
- java基础教程:集合概述(27)
- Unity3D学习记录——刚体跳跃
- TCP/IP小结
- CCF201312-4 有趣的数 不会DP只会枚举
- 06读书笔记之进度条
- docker之daemon.json
- poj3255次短路
- Ubuntu中文版系统文件夹改成英文方法
- 文件上传-commons-fileupload组件
- Activity通信-传递对象、集合总结
- Matlab读取二进制文件
- Python3之列表(list)