1. 程式人生 > >2018ecjtu 雙基 G題

2018ecjtu 雙基 G題

描述:

7的意志
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld
題目描述
定義一個序列a:7,77,777…,7777777(數字全為7的正整數,且長度可以無限大)
clearlove7需要從含有7的意志的數裡獲得力量,如果一個整數能被序列a中的任意一個數字整除,並且其數位之和為序列a中任意一個數字的倍數,那麼這個數字就含有7的意志,現在給你一個範圍[n,m],問這個範圍裡有多少個數字含有7的意志。

輸入描述:
多組輸入,每行兩個個整數n,m(1<=n<=m<=1e18),如果輸入為"0 0",停止程式。
輸出描述:
每一行輸出含有7的意志的數的個數。
示例1
輸入
複製
1 7
1 100
1 1000
0 0
輸出
複製
1
3
21
說明
1到100中符合條件的數字為7,70,77

程式碼:

/* ecjtu 雙基 */
/* 7的意志 */
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#define ll long long
const int mod=1e9+7;
int digits[20];
ll dp[20][10][10];
/*變數
dp[pos][pre][sum] - pos位到0位 的數的和%7的餘數為pre,數位和%7為sum的 個數
sum - 數位和的餘數
pre - 數的餘數 例如113,pre最先取1 -> pre=(pre*10+1)%7 -> pre=(pre*10+3)%7

//之前剛剛學了數位dp,比賽時結果這道題還是做不來,看來沒有理解透數位dp,不過這道題可以讓我更加熟悉


*/
ll dfs(int pos,int pre, int sum,bool limit) { if(pos==-1) return (sum%7==0&&pre%7==0); if(!limit&&dp[pos][pre][sum]!=-1) return dp[pos][pre][sum]; int up=limit?digits[pos]:9; ll ans=0; for(int i=0;i<=up;i++) { ans=ans+dfs(pos-1,(pre*10+i)%7,(sum+i)%7,limit&&
i==digits[pos]); } if(!limit&&dp[pos][pre][sum]==-1) dp[pos][pre][sum]=ans; return ans; } ll solve(ll n) { int len=0; memset(dp,-1,sizeof(dp)); while(n) { digits[len++]=n%10; n/=10; } return dfs(len-1,0,0,true); } int main() { ll n, m; while(scanf("%lld%lld",&n, &m)!=EOF) { if(n==0&&m==0) break; printf("%lld\n",solve(m)-solve(n-1)); } return 0; }