Simple Addition Expression
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2451
题目大意:
有一种计算器,专门用来计算连续的三个数的和,不过这个计算器比较低端,不能够进位。如 0 + 1 + 2 ,计算器算出3,但 3 + 4 + 5 计算器只能算出 2。正确答案是12,由于无法进位。把1直接给扔了。
现在给你一个数N,求 [0,N) 的范围内有多少个数,可以作为连续三个数的第一个数,使得计算器能够算出正确答案。
解题思路:
我的思路是这样的,由于是组合数学专题的题目,于是我就想朝着这方面靠。(然后发现自己的姿势总是不够优美)
首先分析一位数,这个数只能为0,1,2.
其次分析两位数,个位数同上,而十位数可以为1,2,3。
接着分析三位数,个位数同上,十位数可以为0,1,2,3.。而百位数可以为1,2,3.
于是不难发现,对于一个N位数,最高位有3种选择,个位有三种选择,其余位有4种选择。 即 3 * 4 * 4*……* 4 * 3 (N >= 3)
然后我就直接开始看这个数为几位数,如果为N位数,那么从 1 位到 N - 1 位的都很好算。接下来就是算N位数了,而判断N位数就很麻烦了,需要从最高位一个一个推过来,如果最高位是小于等于3的,为k。那么当最高位取1到k - 1时,后面的位数同上,但当最高位取了k时,又要考虑下一位的取值。以此类推,十分麻烦,然后我放弃了,因为发现与其这样不如直接用数位DP来一发。。
数位DP的解法。具体的方法详见代码吧。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<map> #include<queue> #include<stack> #include<vector> #include<set> #include<ctype.h> #include<algorithm> #include<string> #define PI acos(-1.0) #define maxn 1000 #define INF 1<<25 #define mem(a, b) memset(a, b, sizeof(a)) typedef long long ll; using namespace std; int pos, bit[12]; void open(ll n) { pos = -1; while(n) { bit[++pos] = n % 10; n /= 10; } } int f[12][4]; ll dfs(int pos, int s, bool e) { if (pos == -1) return (s != 3); //如果搜到最后一位,即各位的时候,要把 3 给去掉。即s == 3 的时候,return 0 if (!e && f[pos][s] != -1) return f[pos][s]; ll res = 0; int u = e ? bit[pos] : 3; if (u > 3) u = 3; //之前没加这句话,wa了。其实是这样的,u如果等于bit[pos]的话,有可能大于3,而我们根本不需要考虑大于3的情况。要不然就在搜索的时候多算了 for (int d = 0; d <= u; d++) { res += dfs(pos - 1, d, e && d == bit[pos]); } return e ? res : f[pos][s] = res; } void solve(ll n) { mem(f, -1); cout<<dfs(pos, 0, 1)<<endl; } int main () { ll n; while(~scanf("%I64d", &n)) { n--; open(n); solve(n); } return 0; }
后来看了别人的结题报告,发现自己弱爆了。。
其实我完全没必要把数字分为 1 到 N 位来做,直接用N位数来考虑,如果前面有零,不就是位数减少了么。
int main () { ll n; while(cin>>n) //hdu当中long long 类型不能用%lld输入。。给跪了 (第二次被坑了) { open(n); ll ans = 0; bool flag = false; for (int i = pos; i >= 1; i--) { if (bit[i] > 3) flag = true; if (flag) //如果出现某一位大于3,就不用继续循环了 { ans += 3 * pow(4.0, i); //直接把从该位开始的所有情况都加上,并且除了各位,每一位都能取0,1,2,3 四种情况。 break; } ans += bit[i] * 3 * pow(4.0, i - 1); //当bit[i]小于等于3的时候,该位只能去0,1,……bit[i]。 } if (!flag) ans += (bit[0] > 3 ? 3 : bit[0]); //这一步很重要,如果flag为false,及代表着前面都没有bit[i]大于3,就需要判断个位 cout<<ans<<endl; } return 0; }
作者:SIOFive 发表于2013-12-5 0:38:45 原文链接
阅读:173 评论:0 查看评论