思路
毒瘤数位 DP 题。
首先,你可以用一个 vector
储存每一个数字出现的次数,然后用 map
记忆化。
然后可以得到如下 TLE #8 的代码。
因为 map
自带一只 \(\log\) 所以,考虑将 map
优化掉。但是,现在每一种数字可能会出现很多次,所以要用 vector
维护出现次数,但这样必定需要用 map
一类的东西维护。
但是,本题只需要维护每一个数字出现次数的奇偶性,所以,你就可以用二进制来维护一下,这样就把 map
优化掉了。
然后可以得到如下 TLE #11 的代码。
因为 \(q\) 是一个很大的数,然而,我们在每一次记忆化搜索的时候都要 memset(dp,-1,sizeof(dp))
,所以时间复杂度直接降为 \(\Theta(q2^mm)\)。(其中 \(m\) 为数字的长度)
但是,在对于同一个进制 \(s\) 时,每一次相同位置的 \(dp\) 值是相同的,所以,直接再开一维表示进制即可。
Code
#include <bits/stdc++.h>
#define int long long
#define re register
using namespace std;
const int N = 110,M = 2010,K = 15;
int T,s,l,r;
int arr[N];
int dp[K][N][M];
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
inline int dfs(int u,int st,bool z,bool lm){
if (!u) return (!st);
if (!z && !lm && ~dp[s][u][st]) return dp[s][u][st];
int res = 0,Max = s - 1;
if (lm) Max = arr[u];
for (re int i = 0;i <= Max;i++){
if (i || !z) st ^= (1ll << i);
res += dfs(u - 1,st,z && (!i),lm && (i == Max));
if (i || !z) st ^= (1ll << i);
}
if (!z && !lm) dp[s][u][st] = res;
return res;
}
inline int calc(int x){
int len = 0;
while (x){
arr[++len] = x % s;
x /= s;
}
return dfs(len,0,true,true);
}
signed main(){
memset(dp,-1,sizeof(dp));
T = read();
while (T--){
s = read();
l = read();
r = read();
printf("%lld\n",calc(r) - calc(l - 1));
}
return 0;
}
标签:map,CF855E,数字,int,题解,Slytherin,维护,dp
From: https://www.cnblogs.com/WaterSun/p/18263309