2004: 追梦之人
描述
题目描述:
为了纪念追梦人,粉丝们创造了一种新的数——“追梦数”。追梦数要满足以下两个条件:
1、数字中不能出现“7”
2、不能被7整除。
比如:777和4396就不是追梦数,而666是追梦数。现在他们想知道,1到N中有多少个追梦数。
输入:
多组数据。
第一行给出一个正整数T。T为数据组数。
接下来T行,每行包括一个正整数N。
(1 leq T leq 10001≤T≤1000)
(1 leq N leq 10^{18}1≤N≤1018)
输出:
对于每组数据,在单独的一行中输出一个整数表示1到N中有多少个追梦数。
样例输入
4
10
14
17
100
样例输出
9
12
14
70
当初石乐志要维护三个东西,后来发觉数位只要维护两个东西就好了。
我们的答案是n-被7整除的数-不被7整除但包含7的数。
被7整除的数n/7即可求出。
后面这个写个数位dp即可。
注意边界。
1 #include<bits/stdc++.h> 2 #define clr(x) memset(x,0,sizeof(x)) 3 #define clr_1(x) memset(x,-1,sizeof(x)) 4 #define mod 7 5 #define LL long long 6 #define INF 0x3f3f3f3f 7 #define mp make_pair 8 #define pb push_back 9 #define mp make_pair 10 #define fi first 11 #define se second 12 using namespace std; 13 const int N=1e5+10; 14 LL all[30][10][2],num[30]; 15 void init() 16 { 17 all[0][0][0]=1; 18 num[1]=1; 19 for(int i=2;i<=18;i++) 20 num[i]=(num[i-1]*10)%mod; 21 for(int i=1;i<=18;i++) 22 for(int j=0;j<=9;j++) 23 for(int k=0;k<7;k++) 24 if(j!=7) 25 { 26 all[i][(int)(j*num[i]%mod+k)%mod][1]+=all[i-1][k][1]; 27 all[i][(int)(j*num[i]%mod+k)%mod][0]+=all[i-1][k][0]; 28 } 29 else 30 all[i][(int)(j*num[i]%mod+k)%mod][1]+=all[i-1][k][1]+all[i-1][k][0]; 31 } 32 LL n,m,k; 33 LL ans; 34 int a[N],t,now; 35 bool flag; 36 int T; 37 int main() 38 { 39 init(); 40 scanf("%d",&T); 41 while(T--) 42 { 43 scanf("%lld",&n); 44 ans=n-n/7; 45 m=0; 46 n++; 47 while(n) 48 { 49 a[++m]=n%10; 50 n/=10; 51 } 52 now=0; 53 flag=0; 54 for(int i=m;i>=1;i--) 55 { 56 for(int j=0;j<a[i];j++) 57 { 58 for(int k=0;k<mod;k++) 59 if((j*num[i]%mod+k+now)%mod!=0) 60 { 61 ans-=all[i-1][k][1]; 62 if(flag || j==mod) 63 ans-=all[i-1][k][0]; 64 } 65 } 66 now=(now+a[i]*num[i])%mod; 67 if(a[i]==mod) 68 flag=1; 69 } 70 printf("%lld ",ans); 71 } 72 }