牛客国庆集训派对day5 C.Great Deceiver

    科技2022-08-19  97

    题意: 给定 n n n k k k,问在 k k k进制和 − k -k k进制下值相同的数 x x x的个数, x ≤ n x\leq n xn。 数据范围: 1 ≤ n ≤ 1 0 15 , 2 ≤ k ≤ 1000 1\leq n\leq 10^{15}, 2\leq k\leq 1000 1n1015,2k1000

    题解: 转换成 k k k进制考虑下,发现只有当每个奇数位都为 0 0 0,即不会产生负数影响时的数才是合法的数,因此考虑转换成 k k k进制进行数位 d p dp dp,限制奇数位为 0 0 0即可。

    代码:

    #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> #include<stack> #include<queue> #include<map> #include<vector> #include<cmath> using namespace std; typedef long long ll; template<typename T> inline T Read(){ T s = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - '0'; ch = getchar();} return s * f; } #define read() Read<int>() #define readl() Read<long long>() ll n; int k; const int N = 70; int bit[70]; ll dp[N]; ll dfs(int u, bool limit) { //到达了最后一个数 if(u == -1) return 1; //当没有到达顶端且这个数之前已经被计算过了 /* 如 n = 3 4 5 当前是 2 x y, 且u在x这个位置 但是之前 1 x y 时,x 和 y的所有合法情况都被考虑过了,因此不需要再次重复计算 故此时直接返回即可 */ if(!limit && dp[u] != -1) return dp[u]; int last = limit ? bit[u] : (k - 1); if(u & 1) last = 0; ll ans = 0; for(int i = 0; i <= last; i++) { ans += dfs(u - 1, limit && i == bit[u]); } /* 如上,这种情况下dp[u]会被多次使用,故记忆此次避免重复计算 */ if(!limit) dp[u] = ans; return ans; } void solve() { n = readl(), k = read(); ll tn = n; int g = 0; while(tn) { bit[g++] = tn % k; tn /= k; } memset(dp, -1, sizeof dp); printf("%lld\n", dfs(g - 1, true)); } int main() { int T = 1; //T = read(); for(int i = 1; i <= T; ++i) { solve(); } return 0; }
    Processed: 0.023, SQL: 9