[题解]CF855E Salazar Slytherin's Locket

思路

毒瘤数位 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;  
}  
posted @ 2024-06-23 13:00  WBIKPS  阅读(31)  评论(0)    收藏  举报