Hdu 4507 吉哥系列故事——恨7不成妻

[L,R] 中不滿足以下任意一條的數的平方和

1 整數中某一位是7

2 整數的每一位加起來的和是7的整數倍

3 這個整數是7的整數倍;


一眼看去又是一個數位dp,但是怎麼統計平方和呢?

假設我們在統計最高位爲x的n個數的平方和

i=1n(x+a)2=n×x2+2x×i=1nai+i=1na2i

其中和x相關的貢獻是前兩項。也就是說,我們統計能接在當前前綴後面的後綴的個數和後綴的和,就可以計算出x對整個平方和的貢獻。

怎麼統計後綴和呢?

i=1n(x+ai)=n×x+i=1nai

也需要統計後綴的個數。

那麼照着這個統計下去就好了。


因爲一開始寫的時候沒有想太多就強行寫了三遍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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章