原题
当时都没有来得及去想这题,后面补提一直报错,看了下大牛们的操作才恍然大悟。
一道典型的数位dp,记忆化处理加快效率。
Dp【pos】【num1】【num2】,其中,pos存剩下的位数,num1存在已剩下位数中(使用的前提没有上值的限制),满足num1和num2状态的答案(根本不需要去考虑前几个位数是否一致,只要考虑它们在此时的num1和num2的状态一致即可),
ans.sum=(ans.sum+temp.sum+i*bit[ps]temp.cnt%mod)%mod;,这里乘temp.cnt的意思是,在以当前的i为该位,那么后面有多少个满足与6无关的数字,有多少个,加多少个ibit【ps】
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
struct node{
ll cnt,sum; // cnt存数量,sum存答案
node(ll _cnt,ll _sum):cnt(_cnt),sum(_sum){
}
node():cnt(-1),sum(0){
}
}dp[20][10][10];
ll bit[21],pos[20]; // 这里bit数组大小一定要21,20就错了,我也不知道为什么,明明全部小于1e18的
node dfs(int ps,int num1,int num2,int limit){
if( ps==-1 ){
if( num1==0 || num2==0 )
return node(0,0);
else
return node(1,0);
}
if( limit!=1 && dp[ps][num1][num2].cnt!=-1 )
return dp[ps][num1][num2]; // 若以前走过,那么就直接return,不用再次走一遍浪费时间
int up=limit?pos[ps]:9;
node ans;
ans.cnt=0;
for( int i=0 ; i<=up ; i++ ){
if( i==6 )
continue;
node temp=dfs(ps-1,(num1+i)%6,(num2*10+i)%6,i==up&&limit);
ans.cnt=(ans.cnt+temp.cnt)%mod;
ans.sum=(ans.sum+temp.sum+i*bit[ps]*temp.cnt%mod)%mod; // 一个一个加上去
}
if( limit!=1 )
dp[ps][num1][num2]=ans;
return ans;
}
ll solve(ll k){
int len=0;
while( k ){
pos[len++]=k%10;
k/=10;
}
return dfs(len-1,0,0,1).sum;
}
int main()
{
//freopen("input.txt","r",stdin);
bit[0]=1;
ll l,r;
for( int i=1 ; i<=20 ; i++ )
bit[i]=bit[i-1]*10%mod;
while( ~scanf("%lld %lld",&l,&r) ){
printf("%lld\n",(solve(r)-solve(l-1)+mod)%mod);
}
return 0;
}