2zoj 3692 -浙江省赛(数位) Seven Segment Display
/*
特殊处理FFFFFFFF +1的会变成00000000的情况,因为只会变一次,所以判断一下m+n>0xFFFFFFFF就行了
然后问题就简化为了计算00000000-n之间0-f出现的次数,因为算前导0,那么从高位向低位按位枚举就行了
*/
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll INF=0xFFFFFFFF; ll pow16[10]; int d[10]; void dfs(int dep,bool flag,int *c1,int *c2){ if(dep==1){ for(int i=0;i<=d[0];i++)c1[i]++; for(int i=0;i<16;i++)c1[i]+=c2[i]*(d[0]+1); return ; } dep--; //d[dep]出现的次数 for(int i=0;i<d[dep];i++)c1[i]+=pow16[dep]; for(int i=0;i<16;i++){ c1[i]+=pow16[dep]*c2[i]*d[dep];//前面的那些数出现的次数 c1[i]+=pow16[dep-1]*(dep)*d[dep]; } c2[d[dep]]++; dfs(dep,flag,c1,c2); } inline void solve(ll n){ for(int i=0;i<8;i++)d[i]=n%16,n/=16; } inline int getnum(char c){ if(isdigit(c))return c-'0'; return c-'A'+10; } char s[15]; int a[16],b[16],c[16]; int e[]={6,2,5,5,4,5,6,3,7,6,6,5,4,5,5,4}; int main(){ pow16[0]=1; for(int i=1;i<=8;i++)pow16[i]=pow16[i-1]*16; int t,n; scanf("%d",&t); while(t--){ scanf("%d%s",&n,s); ll m=0; for(int i=0;i<8;i++)m=m*16+getnum(s[i]); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); if(m>0){ solve(m-1); memset(c,0,sizeof(c)); dfs(8,1,a,c); } m+=n-1; if(m>INF){ memset(c,0,sizeof(c)); solve(INF); dfs(8,1,b,c); m-=INF+1; memset(c,0,sizeof(c)); solve(m); dfs(8,1,b,c); } else{ memset(c,0,sizeof(c)); solve(m); dfs(8,1,b,c); } ll res=0; for(int i=0;i<16;i++)b[i]-=a[i]; for(int i=0;i<16;i++)res+=(ll)b[i]*e[i]; printf("%lld\n",res); } return 0; }