求
1 整數中某一位是7
2 整數的每一位加起來的和是7的整數倍
3 這個整數是7的整數倍;
一眼看去又是一個數位dp,但是怎麼統計平方和呢?
假設我們在統計最高位爲x的n個數的平方和
有
其中和x相關的貢獻是前兩項。也就是說,我們統計能接在當前前綴後面的後綴的個數和後綴的和,就可以計算出x對整個平方和的貢獻。
怎麼統計後綴和呢?
也需要統計後綴的個數。
那麼照着這個統計下去就好了。
因爲一開始寫的時候沒有想太多就強行寫了三遍dfs。。。
有空重寫一遍
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 20,mod = 1e9 + 7;
int num[maxn];
LL ten[maxn * 2];
LL cnted[maxn][2][7][7];
LL count(int pos,bool bnd,int left,int sumer){
if(pos < 0) return left != 0 && sumer != 0;
LL & ncnt = cnted[pos][bnd][left][sumer];
if(~ncnt) return ncnt;
ncnt = 0;
int bound = bnd ? num[pos] : 9;
for(int i=0;i<=bound;i++){
if(i == 7) continue;
(ncnt += count(pos-1
,bnd && bound == i
,(left * 10 + i ) % 7
,(sumer + i ) % 7 ) ) %= mod;
}
return ncnt;
}
LL sumed[maxn][2][7][7];
LL sum(int pos,bool bnd,int left,int sumer){
if(pos < 0) return 0;
LL & nsum = sumed[pos][bnd][left][sumer];
if(~nsum) return nsum;
nsum = 0;
int bound = bnd ? num[pos] : 9;
for(int i=0;i<=bound;i++){
if(i == 7) continue;
(nsum += sum (pos-1
,bnd && bound == i
,(left * 10 + i ) % 7
,(sumer + i ) % 7 ) ) %= mod;
(nsum += (count(pos-1
,bnd && bound == i
,(left * 10 + i ) % 7
,(sumer + i ) % 7 )
* i
* ten[pos]) % mod ) %= mod;
}
return nsum;
}
LL dp[maxn][2][7][7];
LL dfs(int pos,bool bnd,int left,int sumer){
if(pos < 0) return 0;
LL & ndp = dp[pos][bnd][left][sumer];
if(~ndp) return ndp;
ndp = 0;
int bound = bnd ? num[pos] : 9;
for(int i=0;i<=bound;i++){
if(i == 7) continue;
(ndp += dfs(pos-1
,bnd && bound == i
,(left * 10 + i ) % 7
,(sumer+ i ) % 7 ) ) %= mod;
(ndp += ((count(pos-1
,bnd && bound == i
,(left * 10 + i ) % 7
,(sumer+ i ) % 7 )
* i * i ) % mod
* ten[pos * 2]) % mod ) %= mod;
(ndp += ((sum(pos-1
,bnd && bound == i
,(left * 10 + i ) % 7
,(sumer+ i ) % 7 )
* i * 2 ) % mod
* ten[pos]) % mod ) %= mod;
}
return ndp;
}
LL cal(LL x){
int len = 0;
while(x){
num[len++] = x % 10;
x /= 10;
}
memset(cnted,-1,sizeof(cnted));
memset(sumed,-1,sizeof(sumed));
memset(dp,-1,sizeof(dp));
return dfs(len-1,true,0,0);
}
int main(){
ten[0] = 1;
for(int i=1;i<maxn * 2;i++) ten[i] = (ten[i-1] * 10 ) % mod;
int T;
scanf("%d",&T);
LL l,r;
while(T-- && ~scanf("%I64d %I64d",&l,&r)){
printf("%I64d\n",(cal(r) - cal(l-1) + mod) % mod);
}
return 0;
}
重寫之後果然短了不少
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 20,mod = 1e9 + 7;
LL dp[maxn][2][7][7];
LL sum[maxn][2][7][7];
LL cnt[maxn][2][7][7];
bool vis[maxn][2][7][7];
int num[maxn];
LL ten[maxn * 2];
LL cnter(int pos,bool bnd,int lef,int mor,int nex){
lef = (lef * 10 + nex) % 7;
mor = (mor + nex) % 7;
if(pos == 0)
return mor != 0 && lef != 0;
return cnt[pos-1][bnd && nex == num[pos]][lef][mor];
}
LL sumer(int pos,bool bnd,int lef,int mor,int nex){
if(pos == 0) return 0;
lef = (lef * 10 + nex) % 7;
mor = (mor + nex) % 7;
return sum[pos-1][bnd && nex == num[pos]][lef][mor];
}
#define nexter pos,bnd,lef,mor,i
LL dfs(int pos,bool bnd,int lef,int mor){
if(pos < 0) return 0;
if(vis[pos][bnd][lef][mor])
return dp[pos][bnd][lef][mor];
LL & ndp = dp [pos][bnd][lef][mor];
LL & ncnt = cnt[pos][bnd][lef][mor];
LL & nsum = sum[pos][bnd][lef][mor];
ndp = ncnt = nsum = 0;
int bound = bnd ? num[pos] : 9;
for(int i=0;i<=bound;i++){
if(i == 7) continue;
(ndp += dfs(pos-1,bnd && i == bound,(lef*10+i)%7,(mor+i)%7)) %= mod;
(ncnt += cnter(nexter) ) %= mod;
(nsum += sumer(nexter) ) %= mod;
(nsum += ((cnter(nexter) * i ) % mod * ten[pos] ) % mod ) %= mod;
(ndp += ((cnter(nexter) * i * i ) % mod * ten[pos * 2]) % mod ) %= mod;
(ndp += ((sumer(nexter) * i * 2 ) % mod * ten[pos] ) % mod ) %= mod;
}
vis[pos][bnd][lef][mor] = true;
return ndp;
}
LL cal(LL n){
int len = 0;
while(n){
num[len++] = n % 10;
n /= 10;
}
memset(vis,0,sizeof(vis));
return dfs(len-1,true,0,0);
}
int main(){
ten[0] = 1;
for(int i=1;i<maxn * 2;i++)
ten[i] = (ten[i-1] * 10) % mod;
int T;
scanf("%d",&T);
LL l,r;
while(T-- && ~scanf("%I64d %I64d",&l,&r)){
printf("%I64d\n",(cal(r) - cal(l-1) + mod ) % mod);
}
return 0;
}