数位DP
数位DP题会给你用数位DP的感觉。
dp数组的维度根据题意的限制大胆开,不变的基本上是:现在是第几位、有无限制(最高为限制)、其他限制。
做了几个套路题,一般方法就是记忆化搜索,一般从高位往低位枚举。
来几份板子题代码找找感觉。
Windy 数
#include <iostream>
#include <cmath>
#include <cstdio>
#include <set>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#define Bessie signed
#define Moo ~~
#define int long long
#define re register int
using namespace std;
int read() {
int A = 0, FL = 1;
char C;
C = getchar();
while(C < '0' || C > '9') FL = C=='-' ? -1 : 1 , C = getchar();
while(C >= '0'&& C <= '9')A = (A << 3) + (A << 1) + (C ^ '0'), C = getchar();
return A * FL;
}
#define pc_n putchar('\n')
#define pc_ putchar(' ')
inline int max(int x, int y) {return x > y ? x: y;}
inline int min(int x, int y) {return x < y ? x: y;}
const int N = 25;
int a, b;
int dp[N][N], num[N], top;
int dfs(int tt, int lst, bool ifzero, bool ifhigh) {
if(!tt) return !ifzero;
if(!ifzero && !ifhigh && dp[tt][lst] != -1) return dp[tt][lst];
int mx = ifhigh ? num[tt] : 9;//最高位有没有限制
int res = 0;
for(re i = 0; i <= mx; ++i)
if(ifzero || abs(i - lst) >= 2)
res += dfs(tt - 1, i, ifzero && i==0, ifhigh && i==mx);
if(!ifzero && !ifhigh)
dp[tt][lst] = res;
return res;
}
int cnt(int x) {
memset(dp, -1, sizeof(dp));
top = 0;
while(x) {
num[++top] = x % 10;
x /= 10;
}
return dfs(top, 0, 1, 1);
}
Bessie main() {
a = read(), b = read();
printf("%lld\n", cnt(b) - cnt(a - 1));// 差分思想, 这样只需考虑上界即可
return 0;
}
花神的数论题
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <cstring>
#include <map>
using namespace std;
#define int long long
#define re register int
#define pc_n printf("\n")
#define pc_ printf(" ")
#define Bessie signed
int read() {
int a = 0, fl = 1;
char c;
c = getchar();
while(c < '0' || c > '9') fl = c=='-' ? -1 : 1, c = getchar();
while(c >= '0' && c <= '9') a = (a << 3) + (a << 1) + (c ^ '0'), c = getchar();
return a * fl;
}
const int MOD = 1e7 + 7;
int n;
int qpow(int x, int y) {
int base = 1;
while(y) {
if(y & 1)
base = base * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return base;
}
int f[55][55][55][2];
int cnt[55], x[55], tot;
int dfs(int tp, int tmp, int sum, int lit) {
//从高往低填, tp -> 当前填到第几位, tmp -> 填了几个一了, sum -> 目标要填几个一, lit -> 是否受限
if(!tp)
return tmp == sum;
if(f[tp][tmp][sum][lit] != -1)
return f[tp][tmp][sum][lit];
int maxx = lit ? x[tp] : 1;
int res = 0;
for(re i = 0; i <= maxx; ++i) {
res += dfs(tp - 1, tmp + (i == 1), sum, lit && (i == maxx));
}
return f[tp][tmp][sum][lit] = res;
}
int solve() {
while(n) {
x[++tot] = n & 1;
n >>= 1;
}
for(re i = 1; i <= 52; ++i) {
memset(f, -1, sizeof(f));
cnt[i] = dfs(tot, 0, i, 1);
}
int ans = 1;
for(re i = 1; i <= 52; ++i) {
ans = ans * qpow(i, cnt[i]) % MOD;
}
return ans;
}
Bessie main() {
n = read();
printf("%lld\n", solve());
return 0;
}
手机号码
#include <iostream>
#include <cmath>
#include <cstdio>
#include <set>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#define Bessie signed
#define Moo ~~
#define int long long
#define re register int
using namespace std;
int read() {
int A = 0, FL = 1;
char C;
C = getchar();
while(C < '0' || C > '9') FL = C=='-' ? -1 : 1 , C = getchar();
while(C >= '0'&& C <= '9')A = (A << 3) + (A << 1) + (C ^ '0'), C = getchar();
return A * FL;
}
#define pc_n putchar('\n')
#define pc_ putchar(' ')
inline int max(int x, int y) {return x > y ? x: y;}
inline int min(int x, int y) {return x < y ? x: y;}
const int N = 25, MOD = 1e7 + 7;
int l, r;
int num[N];
int tp;
int dp[15][12][12][2][2][2];
int dfs(int tt, int lst, int llst, bool three, bool four, bool eight, bool ifhigh) {
if(four && eight) return 0;
if(!tt) return three;
if(!ifhigh && dp[tt][lst][llst][three][four][eight] != -1)
return dp[tt][lst][llst][three][four][eight];
int res = 0, mx = ifhigh ? num[tt] : 9;
for(re i = 0; i <= mx; ++i) {
res += dfs(tt - 1, i, lst, three || (i == lst && i == llst), four || (i == 4), eight || (i == 8), ifhigh && (i == mx));
}
if(!ifhigh)
dp[tt][lst][llst][three][four][eight] = res;
return res;
}
int cnt(int x) {
memset(dp, -1, sizeof(dp));
tp = 0;
while(x) {
num[++tp] = x % 10;
x /= 10;
}
if(tp != 11) return 0;
int ans = 0;
for(re i = 1; i <= num[tp]; ++i) {
ans += dfs(tp - 1, i, 0, 0, i == 4, i == 8, i == num[tp]);
}
return ans;
}
Bessie main() {
l = read(), r = read();
printf("%lld\n", cnt(r) - cnt(l - 1));
return 0;
}