2. 黄月英
(huangyueying.cpp/c/pas )
【问题描述】
xpp 每天研究天文学研究哲学,对于人生又有一些我们完全无法理解的思考。
在某天无聊学术之后, xpp 打开了 http://web.sanguosha.com, 准备用他心爱的黄月英
虐人。进入了八人身份局,作为一位主公,xpp 果断选了黄月英,用黄月英挑 7 人。
xpp 为什么喜欢黄月英这个武将呢?因为集智是个很牛逼的技能。
集智——每当你使用一张非延时类锦囊(在它结算之前)你可以立即摸一张牌。
可见集智这个技能如果用得好那么牌是摸不完的。于是 xpp 把 7 个人全部轻松干掉。
虽然 xpp 的集智永远都能摸锦囊, 但是他想到了这样一个问题: 由于黄月英是一个富有
智慧的人,所以 xpp 也要想一个富有智慧的问题,具体说来,他对牌上的数字产生了兴趣,
于是他想知道,牌上每个数字出现过多少次。
当然,要算牌上的数字太简单了。所以 xpp 要扩大范围。
xpp 正在考虑这样一个问题:从一个数字 a 到另一个数字 b 之间,从 0 到 9 的每个数字
出现过多少次。
xpp 智商过于强大,不屑于想此等低端问题,然后你就要把这道题做出来。
【输入】
输入文件名为 huangyueying.in。
共一行,每行两个整数,分别为 a,b。
【输出】
输出文件名为 huangyueying.out。
输出共一行,包含 10 个整数,分别代表从 0 到 9 的数字各出现过多少次。
【输入输出样例】
huangyueying.in huangyueying.out
24 69 4 4 10 14 15 15 15 5 5 5
【数据范围】
对于 30%的数据,a≤b≤1000000。
对于 100%的数据,a≤b≤10^12。
————————————————题解
一道极为水的数位dp,但我一直没调出来
原先统计的时候没有统计前缀0,单纯算每个数,觉得去前导0太麻烦,然后就再也调不通了,后来看题解发现其实去的话也不是那么麻烦……然后就过了
【老司机的数据十分坑】
就是我们算4997,我们加上000-
1 #include <iostream> 2 #include <string.h> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <algorithm> 6 #include <cstring> 7 #include <vector> 8 #include <ctime> 9 #define ivorysi 10 #define mo 10007 11 #define siji(i,x,y) for(int i=(x);i<=(y);i++) 12 #define gongzi(j,x,y) for(int j=(x);j>=(y);j--) 13 #define xiaosiji(i,x,y) for(int i=(x);i<(y);i++) 14 #define sigongzi(j,x,y) for(int j=(x);j>(y);j--) 15 #define ivory(i,x) for(int i=head[x];i;i=edge[i].next) 16 #define pii pair<int,int> 17 #define fi first 18 #define se second 19 #define inf 10000000 20 using namespace std; 21 typedef long long ll; 22 ll dp[15][15][15];//dp(i,j,k)i位数,j开头,k的个数 23 ll num[12]={//为啥我sb到打了这个表 24 0, 25 10, 26 100, 27 1000, 28 10000, 29 100000, 30 1000000, 31 10000000, 32 100000000, 33 1000000000LL, 34 10000000000LL, 35 100000000000LL 36 }; 37 void init() { 38 siji(i,0,9) { 39 dp[1][i][i]=1; 40 } 41 siji(i,2,12) { 42 siji(j,0,9) { 43 siji(k,0,9) { 44 siji(h,0,9) { 45 dp[i][j][k]+=dp[i-1][h][k]; 46 } 47 } 48 dp[i][j][j]+=num[i-1]; 49 } 50 } 51 siji(i,1,12) { 52 siji(j,1,9) { 53 siji(k,0,9) { 54 dp[i][j][k]+=dp[i][j-1][k]; 55 } 56 } 57 } 58 } 59 ll a,b; 60 ll ansa[15],ansb[15]; 61 void query(ll c,ll *arr) { 62 if(c==-1) return ; 63 ll tmp=c; 64 int len=0,x[15]; 65 while(tmp) { 66 x[++len]=tmp%10; 67 tmp/=10; 68 } 69 gongzi(i,len,2) { 70 if(x[i]!=0) { 71 siji(k,0,9){ 72 arr[k]+=dp[i-1][9][k]; 73 } 74 if(i==len) siji(k,1,i-2) arr[0]-=num[k]; 75 /* 76 假如我们做的是000-999 77 我们要搞掉000-009两次0 78 搞掉010-099一次0 79 这要合起来我们搞一遍000-099一次0(100个0) 80 搞000-009一次0(10个0) 81 */ 82 if(i!=len)arr[0]+=num[i-1]; 83 } 84 xiaosiji(p,1,x[i]) { 85 siji(k,0,9) { 86 arr[k]+=dp[i-1][9][k]; 87 } 88 arr[p]+=num[i-1]; 89 } 90 arr[x[i]]+=c%num[i-1]+1;//加上这一位后面数 91 } 92 siji(i,0,x[1]) ++arr[i]; 93 } 94 int main() { 95 #ifdef ivorysi 96 freopen("huangyueying.in","r",stdin); 97 freopen("huangyueying.out","w",stdout); 98 #else 99 freopen("f1.in","r",stdin); 100 #endif 101 scanf("%I64d%I64d",&a,&b); 102 init(); 103 query(a-1,ansa); 104 query(b,ansb); 105 siji(i,0,9) { 106 printf("%I64d%c",ansb[i]-ansa[i]," \n"[i==9]); 107 } 108 return 0; 109 }
999(搞掉前缀0),加上1000-1999,加上2000-2999,加上3000-3999,加上998个4,然后我们再搞下一位……第一位4我们可以扔掉不管
正确性写个暴力对拍就知道了