2018ecjtu 雙基 G題
阿新 • • 發佈:2018-12-22
描述:
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;
}