数位DP

数位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 }
View Code

裸的数位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.搞清楚函数的参数的意义...位数加一减一什么的......

原文地址:https://www.cnblogs.com/DragoonKiller/p/4423313.html