CCF201312-4 有趣的数 不会DP只会枚举
2017-07-15 09:39
176 查看
========================================= 原题 ============================================
问题描述我们把一个数称为有趣的,当且仅当:
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; }
相关文章推荐
- CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)
- 【HDU】5905 Black White Tree【树dp,枚举子树,对于一个a,其对应的可行b一定是一个连续区间】
- (CCF 201312-4)有趣的数 [DP] 最详细解答
- POJ 1050 To the Max 枚举+dp
- Fzu 2200 cleaning【环状Dp-----暴力枚举拆环】
- SCU 4488 king's trouble II(dp||枚举)
- Q - Phalanx 【枚举+DP】
- HDU-1058 Humble Numbers(线性dp 枚举因子个数)
- codevs 3162 抄书问题 (dp+枚举输出位置)
- BZOJ1444:[Jsoi2009]有趣的游戏 (AC自动机+概率DP+高斯消元)
- 【Usaco2015 JAN】Moovie Mooving【DP】(发现自己有点不会写二分啊)
- POJ 1745:Divisibility 枚举某一状态的DP
- POJ 1178 - Camelot (枚举+dp : floyd)
- Codeforces Round #116 (Div. 2, ACM-ICPC Rules) Letter(DP 枚举)
- HDU 3721 Building Roads 树形dp + 枚举直径
- poj 3140 Contestants Division(树形dp? dfs计数+枚举)
- 【BZOJ1183】[Croatian2008]Umnozak【数位DP】【质因数分解】【枚举】【记忆化搜索】
- SCU 4488 king's trouble II(dp||枚举)
- BZOJ 1046 DP 逆求最长下降序列+枚举
- 第一次CCF-4-有趣的数(DP)