题意:给一个16进制8位数,给定每个数字的贡献,问你贡献和。
思路:数位DP,想了很久用什么表示状态,看题解说用和就行,其他的都算是比较正常的数位DP。
代码:
#include<iostream> #include<stdio.h> #include<cmath> #include<string> #include<queue> #include<set> #include<vector> #include<string.h> #include<algorithm> typedef long long int ll; using namespace std; const int maxn = 1e5 + 5; const int inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; ll dp[10][105]; int bit[12]; int num[18] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6, 6, 5, 4, 5, 5, 4}; ll dfs(int pos, int sum, bool limit){ if(pos < 0) return sum; if(!limit && dp[pos][sum] != -1) return dp[pos][sum]; int top = limit? bit[pos] : 15; ll ret = 0; for(int i = 0; i <= top; i++){ ret += dfs(pos - 1, sum + num[i], limit && i == top); } if(!limit) dp[pos][sum] = ret; return ret; } ll solve(ll x){ if(x < 0) return 0; ll ans = 0; int pos = 0; memset(bit, 0, sizeof(bit)); while(x > 0){ bit[pos++] = x % 16; x /= 16; } ans = dfs(7, 0, true); return ans; } char s[10]; int main(){ ll fac = 0; for(int i = 0; i < 8; i++) fac = fac * 16 + 15; int T; memset(dp, -1, sizeof(dp)); scanf("%d", &T); while(T--){ ll n, ans = 0; scanf("%lld%s", &n, s); int pos = 0; ll m = 0, M; for(int i = 0; i < 8; i++){ int c = s[i] >= 'A'? 10 + s[i] - 'A' : s[i] - '0'; m = m * 16 + c; } M = m + n - 1; if(M > fac){ ans += solve(fac) - solve(m - 1); ans += solve(M - fac - 1); } else{ ans += solve(M) - solve(m - 1); } printf("%lld ", ans); } return 0; }