2020年Acm暑期考核Hznu _2797
题目链接:http://acm.hznu.edu.cn/OJ/problem.php?id=2797
题意:求1-N中有多少数字满足:
- x是正整数且无前导0。
- x(mod 666) = S(x)。
- 6在x这个数的各数位上出现的总次数必须为奇数。
题解:数位dp模板题(当时考核的时候忘记了板子当场去世)
Ac代码:
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<cstring> 5 #include<cstdio> 6 using namespace std; 7 #define mem(s,n) memset(s,n,sizeof s); 8 #define ios {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); } 9 typedef long long ll; 10 const int maxn=5e6+1; 11 const int Inf=0x7f7f7f7f; 12 const ll Mod=1e9+7; 13 int dp[55][2][500][667]; 14 string s; 15 int dfs(int now,int last,int sum,int mod,bool lim)//now表示当前位数,last=0表示前面有偶数个6,last=1表示前面有奇数个6,sum表示 16 { // 前几位数之和,mod表示对666取余后的数字,lim判断是否达到上界。 17 if(now==-1) 18 { 19 if(mod==sum&&(last&1)) return 1; 20 //last & 1 这个表达式可以用来判断last的奇偶性。二进制的末位为0表示偶数,最末位为1表示奇数 21 return 0; 22 } 23 if(!lim&&~dp[now][last&1][sum][mod]) return dp[now][last&1][sum][mod]; 24 int up=lim?s[now]-'0':9; 25 ll ans=0; 26 for(int i=0;i<=up;i++) 27 { 28 ans+=dfs(now-1,last+(i==6),sum+i,(mod*10+i)%666,lim&&i==up); 29 ans%=Mod; 30 } 31 if(!lim) dp[now][last&1][sum][mod]=ans; 32 return ans; 33 } 34 int main() 35 { 36 int t; 37 scanf("%d",&t); 38 mem(dp,-1); 39 while(t--) 40 { 41 cin>>s; 42 reverse(s.begin(),s.end());//倒置函数因为要从最高位开始。 43 printf("%d\n",dfs(s.length()-1,0,0,0,1)); 44 } 45 return 0; 46 }