就是统计1~n中出现的各个数字的次数,当然是在16进制下。
不过有个区间问题的小技巧,统计从 [x,y] 可以转换成 从 [1,y] 减去 [1,x-1]。
不过要分类讨论一下,因为有可能会出现溢出,从ffffffff +1 得到 00000000 就是溢出了。
因为 n < 1e9 所以只会溢出一次。
// 290ms
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cmath> #include<cctype> const int cost[] = {6,2,5,5,4,5,6,3, 7,6,6,5,4,5,5,4}; long long solve(long long n, int k) { long long i = 1; // 位数 long long cnt = 0; long long low = 0; long long tmp = n; while(n) { long long t = n % 16; n /= 16; low = tmp % i; if(t < k) { cnt += n*i; } else if(t > k) { cnt += (1+n)*i; } else { cnt += n*i; cnt += low+1; } i *= 16; } return cnt; } int Hex(char c){ if(isdigit(c)) return c-'0'; return c - 'A' + 10; } int main() { int t; scanf("%d",&t); for(int i=0;i<t;i++){ long long n; long long x=0; char str[15]; scanf("%lld%s",&n,str); for(int i=0;i<8;i++) x = (x<<4) + Hex(str[i]); long long cnt = 0; long long ans = 0; if((n-1)+x <= 4294967295ll){ // 没有溢出 long long tmp; for(int i=1;i<16;i++){ tmp = solve((n-1ll)+x,i); cnt += tmp; ans += tmp*cost[i]; } for(int i=1;i<16;i++){ tmp = solve(x-1,i); cnt -= tmp; ans -= tmp*cost[i]; } ans += (n*8-cnt)*cost[0]; }else { long long tmp; for(int i=1;i<16;i++){ tmp = solve(4294967295ll,i); cnt += tmp; ans += tmp*cost[i]; } for(int i=1;i<16;i++){ tmp = solve(x-1,i); cnt -= tmp; ans -= tmp*cost[i]; } for(int i=1;i<16;i++){ tmp = solve((n-2ll)+x-4294967295ll,i); cnt += tmp; ans += tmp*cost[i]; } ans += (n*8-cnt)*cost[0]; } printf("%lld ",ans); } return 0; }
搜了一下题解发现可以用数位dp做。。
当时倒是也想到了数位dp但是因为做过的都是不定长的,所以就没有想到可以定长为8。
// 250ms
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cmath> #include<cstring> #include<cctype> int digit[16]; long long dp[10][100]; const int cost[] = {6,2,5,5,4,5,6,3, 7,6,6,5,4,5,5,4}; long long dfs(int d,int sum,bool shangxian){ if(d == 0)return sum; if(!shangxian && dp[d][sum] != -1) return dp[d][sum]; int maxn = shangxian?digit[d]:15; long long tmp = 0; for(int i=0;i<=maxn;i++){ tmp += dfs(d-1,sum+cost[i],shangxian && i==maxn); } return shangxian?tmp:dp[d][sum]=tmp; } long long solve(long long x){ int k = 0; if(x<0)return 0; memset(digit,0,sizeof(digit)); while(x){ digit[++k] = x % 16; x /= 16; } return dfs(8,0,1); } int Hex(char c){ if(isdigit(c)) return c-'0'; return c - 'A' + 10; } int main() { int t; memset(dp,-1,sizeof(dp)); scanf("%d",&t); while(t--){ long long n; long long x=0; char str[15]; scanf("%lld%s",&n,str); for(int i=0;i<8;i++) x = (x<<4) + Hex(str[i]); // 4294967295ll if(x+n-1 <= 4294967295ll) printf("%lld ",solve(x+n-1)-solve(x-1)); else printf("%lld ", solve(4294967295ll)-solve(x-1)+solve(x+n-2-4294967295ll)); } return 0; }