题解 P2518 【[HAOI2010]计数】
这……为啥好好的数位dp题的题解里没一个是数位dp的???
这里上一个比较暴力但是能过跑的还挺快的纯数位dp做法。
首先这题的题意是求
然后这状态没法用数组开下,于是我们可以使用一种最无脑的方法就是开个哈希表然后用bfs转移……具体来说,我们用一个小技巧,注意到这状态里的东西都不超过255,开2个unsigned long long“当做”char数组存,就是这样的:
((char*)&data)[x]
这个就相当于把一个unsigned long long 变量data当做char数组来用,取x下标的位置,注意x必须小于8。这个技巧在一些状态比较复杂的状压dp里配合hash表一块用会非常好用另外orz一下教会我这个的卡常之王shadowice1984
然后空间可能不太能开的下,其实可以在逐位dp的时候把hash表滚动一下就行了。
上代码~
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define p 1000003
#define ull unsigned long long
using namespace std;
namespace ywy {
char str[55];
typedef struct _zt {
ull a, b;
_zt() {
a = 0;
b = 0;
}
inline int get(int x) {
if (x < 8)
return (((char *)&a)[x]);
x -= 8;
return (((char *)&b)[x]);
}
inline void set(int x, int num) {
if (x < 8)
((char *)&a)[x] = num;
else
((char *)&b)[x - 8] = num;
}
inline int hsh() {
ull cjr = a;
cjr %= p;
cjr <<= 32;
cjr |= (b % p);
return (cjr % p);
}
friend bool operator==(const _zt &a, const _zt &b) { return (a.a == b.a && a.b == b.b); }
} zt;
typedef struct _n {
zt data;
ll dp;
int nxt;
} node;
typedef struct _hsh {
node memchi[1000001];
int heads[1000004], gn = 1;
inline void clear() {
memset(heads, 0, sizeof(heads));
gn = 1;
}
inline ll query(zt dat) {
int h = dat.hsh();
for (register int i = heads[h]; i; i = memchi[i].nxt) {
if (memchi[i].data == dat)
return (memchi[i].dp);
}
return (0);
}
inline int insert(zt dat, ll dp) {
int h = dat.hsh();
for (register int i = heads[h]; i; i = memchi[i].nxt) {
if (memchi[i].data == dat) {
memchi[i].dp += dp;
return (0);
}
}
memchi[gn].data = dat;
memchi[gn].dp = dp;
memchi[gn].nxt = heads[h];
heads[h] = gn;
gn++;
return (1);
}
} hsh;
hsh ha[2];
int cnt[2];
zt que[2][1000001];
void ywymain() {
cin >> str + 1;
int n = strlen(str + 1);
reverse(str + 1, str + 1 + n);
zt ztz11;
for (register int i = 1; i <= n; i++) {
if (str[i] != '0') {
int cjr = ztz11.get(str[i] - '0');
cjr++;
ztz11.set(str[i] - '0', cjr);
}
}
cnt[n & 1] = 1;
ztz11.set(10, 1);
que[n & 1][0] = ztz11;
ha[n & 1].insert(ztz11, 1);
for (register int i = n; i >= 1; i--) {
ha[(i & 1) ^ 1].clear();
cnt[(i & 1) ^ 1] = 0;
for (register int j = 0; j < cnt[i & 1]; j++) {
zt me = que[i & 1][j];
ll dp = ha[i & 1].query(me);
for (register int k = 0; k <= ((me.get(10)) ? (str[i] - '0') : 9); k++) {
zt cjr = me;
if (k && !cjr.get(k))
continue;
if (k)
cjr.set(k, cjr.get(k) - 1);
if (me.get(10) && k < str[i] - '0')
cjr.set(10, 0);
if (ha[(i & 1) ^ 1].insert(cjr, dp))
que[(i & 1) ^ 1][cnt[(i & 1) ^ 1]] = cjr, cnt[(i & 1) ^ 1]++;
}
}
}
cout << ha[0].query(_zt()) << endl;
}
}
int main() {
ywy::ywymain();
return (0);
}