数位DP的题曾经写过,但是就是各种混乱不堪=w=
这次写的记忆化搜索....
AC BZOJ 1833
1 #include <cstdio>
2 #include <fstream>
3 #include <iostream>
4
5 #include <cstdlib>
6 #include <cstring>
7 #include <algorithm>
8 #include <cmath>
9
10 #include <queue>
11 #include <vector>
12 #include <map>
13 #include <set>
14 #include <stack>
15 #include <list>
16
17 typedef unsigned int uint;
18 typedef long long int ll;
19 typedef unsigned long long int ull;
20 typedef double db;
21
22 using namespace std;
23
24 inline int getint()
25 {
26 int res=0;
27 char c=getchar();
28 bool mi=false;
29 while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
30 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
31 return mi ? -res : res;
32 }
33 inline ll getll()
34 {
35 ll res=0;
36 char c=getchar();
37 bool mi=false;
38 while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
39 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
40 return mi ? -res : res;
41 }
42
43 //==============================================================================
44 //==============================================================================
45 //==============================================================================
46 //==============================================================================
47
48
49 struct Counter
50 {
51 ll a[10];
52
53 Counter(const Counter&f){ memcpy(a,f.a,sizeof(a)); }
54 Counter(){ memset(a,0,sizeof(a)); }
55
56 ll&operator[](const int&k)
57 { return a[k]; }
58
59 Counter operator+(Counter f)
60 {
61 Counter c;
62 for(int i=0;i<10;i++) c[i]=a[i]+f.a[i];
63 return c;
64 }
65
66 Counter operator-(Counter f)
67 {
68 Counter c;
69 for(int i=0;i<10;i++) c[i]=a[i]-f.a[i];
70 return c;
71 }
72
73 Counter operator*(const ll&k) //这里注意.....
74 {
75 Counter c;
76 for(int i=0;i<10;i++) c[i]=a[i]*k;
77 return c;
78 }
79
80 Counter operator+=(Counter f)
81 { for(int i=0;i<10;i++) a[i]+=f.a[i]; return *this; }
82
83 Counter operator=(Counter f)
84 { memcpy(a,f.a,sizeof(a)); return *this; }
85
86 void Output()
87 { printf("%lld",a[0]); for(int i=1;i<10;i++) printf(" %lld",a[i]); }
88 };
89
90 ll Pow(ll a,ll b) //a^b
91 { ll res=1; for(ll i=0;i<b;i++) res*=a; return res; }
92
93 Counter cpr[10][20];
94 bool cpu[10][20];
95 Counter CountPre(ll v,ll dig) //from (v0..0) to (v99..9)
96 {
97 Counter res;
98 if(dig==0) { return res; }
99 if(cpu[v][dig]) return cpr[v][dig];
100 cpu[v][dig]=true;
101 if(dig==1) { res[v]++; return cpr[v][dig]=res; }
102 for(ll i=0;i<10;i++)
103 res+=CountPre(i,dig-1);
104 res[v]+=Pow(10,dig-1);
105 return cpr[v][dig]=res;
106 }
107
108 Counter cpb[10][20];
109 bool cbu[10][20];
110 Counter CountBeg(ll v,ll dig)
111 {
112 Counter res;
113 if(dig==0) { return res; }
114 if(cbu[v][dig]) return cpb[v][dig];
115 cbu[v][dig]=true;
116 if(dig==1) { for(ll i=0;i<=v;i++) res[i]++; return cpb[v][dig]=res; }
117 res+=CountBeg(9,dig-1);
118 for(ll i=1;i<=v;i++)
119 res+=CountPre(i,dig);
120 return cpb[v][dig]=res;
121 }
122
123
124
125 ll v[20]; //digits divided.
126 ll t=0;
127 Counter GetCount(ll x) //Count from 0 to x.
128 {
129 Counter res;
130
131 if(x<10)
132 {
133 for(ll i=0;i<=x;i++)
134 res[i]++;
135 return res;
136 }
137
138 if(x<100)
139 {
140 for(ll i=0;i<=9;i++)
141 res[i]++;
142 for(ll i=10;i<=x;i++)
143 res[i/10]++,res[i%10]++;
144 return res;
145 }
146
147 t=0;
148 ll _k=x;
149 while(_k!=0)
150 v[t++]=_k%10,_k/=10;
151
152 Counter base;
153
154 res+=CountBeg(v[t-1]-1,t);
155 base[v[t-1]]++;
156
157 for(ll d=t-2;d>=0;d--) //deal with digit d+1.
158 if(v[d]!=0)
159 {
160 res+=base*(Pow(10,d)*v[d]);
161 for(ll i=0;i<v[d];i++) res+=CountPre(i,d+1);
162 base[v[d]]++;
163 }
164 else base[0]++;
165
166 if(x==0) res[0]++;
167 else
168 while(x!=0)
169 res[x%10]++,x/=10;
170
171 return res;
172 }
173
174 int main()
175 {
176 ll L=getll();
177 ll R=getll();
178 (GetCount(R)-GetCount(L-1)).Output();
179
180 return 0;
181 }
裸的数位DP.
主要思路:
将统计的所有数按照某个规则分解成许多组.
一般从高位往低位扫,然后以当前位数-1作一个分割点.
下面以数字 360734 作例子说明.
要分成两个大的部分.
第一部分: 0到299999 .这部分直接特殊处理.
第二部分: 300000到360734 .这部分递推处理.
第二部分的统计数可以继续进行分组:
300000到359999 (当前第5位),
360000 不进行分组(因为当前数位为0,当前第四位),
360000到360699 (当前第三位),
360700到360729 (当前第二位),
360730到360733 (当前第一位),
最后剩下 360734.
计算结果,一般要搞到两个函数值:
1.从 $0$ 到 $a*{10}^{dig}$ 的统计值 $B(0,dig)$ 程序中为 $CountBeg()$ 函数.
2.从 $a*{10}^{dig}$ 到 $a*{10}^{dig}+({10}^{dig}-1)$ 的统计值(即,a00..00到a99..99) 程序中为 $CountPre()$ 函数.
然后根据这个函数值对每个分组进行统计.
要注意的地方:
1.某些地方要打longlong的别漏了.....
2.搞清楚函数的参数的意义...位数加一减一什么的......