nowcoder A hard problem /// 數位DP

題目大意:c++

稱一個數x的各個數位之和爲f(x)spa

求區間L R之間 有多少個數x%f(x)==0code

 

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define inc(i,j,k) for(int i=j;i<=k;i++)
#define dec(i,j,k) for(int i=j;i>=k;i--)
#define gcd(i,j) __gcd(i,j)
#define mem(i,j) memset(i,j,sizeof(i))
const int N=2e5+5;

int rd, dfn[2][15][50][50];
int fx, tot, a[15];
LL dp[2][15][50][50];
// dp[f][w][s][m]
// f爲1說明不是上界 此時爲第w位數 
// 剩下的數位總和爲s 此時的數位總和%f(x)爲m

LL DFS(int f,int w,int s,int m) {
    if(w==0) return (s==0&&m==0);
    // 全部位都枚舉過了則w=0
    // 全部數位總和爲fx則s=0
    // x%fx==0則m=0
    if(dfn[f][w][s][m]==rd) return dp[f][w][s][m];
    dfn[f][w][s][m]=rd;
    LL res=0LL;
    int l=max(0,s-9*(w-1)), r=min((f ? 9:a[w]),s);
    for(int i=l;i<=r;i++) // 枚舉當前位的數
        res+=DFS(f|(i<a[w]),w-1,s-i,(m*10+i)%fx);
    // 以前不是上界 或 當前位不是上界 則到目前爲止都不達上界
    // 位數-1 剩餘數位總和需減去當前位的數 更新餘數
    return dp[f][w][s][m]=res;
}

LL solve(int x) {
    mem(dp,0); mem(dfn,0);
    int tot=0;
    while(x) { a[++tot]=x%10; x/=10; }
    int all=tot*9;
    LL res=0LL;
    for(fx=1;fx<=all;fx++) // 枚舉全部數位總和
        ++rd, res+=DFS(0,tot,fx,0);
    //printf("%lld\n",res);
    return res;
}

int main()
{
    int _; scanf("%d",&_);
    inc(i,1,_) {
        int l,r; scanf("%d%d",&l,&r); rd=0;
        printf("Case %d: ",i);
        printf("%lld\n",solve(r)-solve(l-1));
    }

    return 0;
}
相關文章
相關標籤/搜索