首页 > 技术文章 > 2020年Acm暑期考核Hznu _2797

zpj61 2020-08-09 19:09 原文

题目链接:http://acm.hznu.edu.cn/OJ/problem.php?id=2797

题意:求1-N中有多少数字满足:

  1. x是正整数且无前导0。
  2. x(mod 666) = S(x)。
  3. 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 }

 

推荐阅读