数位DP

来源:互联网 发布:淘宝建设合同范本 编辑:程序博客网 时间:2024/05/16 00:28
 

CodeForces 55D : Beautiful numbers

题意 : 求 【L,R】之间能被自己每一位非0数整除的数的个数。

1-9的LCM是比较小的, 但是直接开会爆, 需要离散化, 这题关键 lcm 和 离散了

#include<bits/stdc++.h>using namespace std;const int maxn = 2520;int gcd(int a, int b) {return b ? gcd(b, a%b): a; }int lcm(int a, int b) {return a / gcd(a, b) * b;  }int index[maxn + 50];void Get_Index(){    int l = 0;    for(int i = 1; i <= maxn; ++i)    {        if(maxn % i == 0)            index[i] = l++;    }}typedef long long LL;LL Dp[50][maxn][100];int Num[100];LL DFS(int L, int sum, int mod, bool e) {    if(L == -1) return sum % mod == 0;    if(!e && Dp[L][sum][index[mod]] != -1) return Dp[L][sum][index[mod]];    int u = e ? Num[L] : 9;    LL ret = 0;    for(int i = 0; i <= u; ++i)        ret += DFS(L-1, (sum*10+i)%maxn, i?lcm(mod, i):mod, e&&(i==u));    return e ? ret : Dp[L][sum][index[mod]] = ret;}LL Solve(LL N) {    int L = 0;    while(N) {        Num[L++] = N%10;        N/=10;    }    return DFS(L-1,0,1,1);}int main(){    Get_Index();    int t;    LL A, B;    cin >> t;    memset(Dp, -1, sizeof(Dp));    while(t--)    {        cin >> A >> B;        LL Ans = A ? (Solve(B)-Solve(A-1)) : Solve(B);        cout << Ans << endl;    }}

 HDU 4352 XHXJ's LIS

题意 : 求数字的位数数升序刚好为 K 的数的个数。

直接状态不好开, 平常我们求LIS 的思想, 可以转化, 状态压缩, 用二进制的 1 的个数表是 LIS 的长度

#include<bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 1<<11;LL Dp[20][maxn][11];LL Num[20], A, B, K;int GetOne(int s) {    int ret = 0;    while(s) {        if(s & 1) ret ++;        s >>= 1;    }    return ret;}int GetState(int n, int s) {    /// 运用 二分求 LIS 的思想    for(int i = n; i < 10; ++i)        if(s&(1<<i)) return (s^(1<<i))|(1<<n);    return s|(1<<n);}LL DFS(int L, int state, bool isz, bool e) {    if(L == -1) return GetOne(state) == K;    if(!e && Dp[L][state][K] != -1) return Dp[L][state][K];    int u = e ? Num[L] : 9;    LL ret = 0;    for(int i = 0; i <= u; ++i)        ret += DFS(L-1, (isz&&(i==0))?0:GetState(i,state), (isz&&(i==0)), e&&(i==u));    return e ? ret : Dp[L][state][K] = ret;}LL Solve(LL N) {    int L = 0;    while(N) {        Num[L++] = N % 10;        N /= 10;    }    return DFS(L-1, 0, 1, 1);}int main(){    memset(Dp,-1,sizeof(Dp));    int t;    scanf("%d", &t);    for(int kase = 1; kase <= t; ++kase) {        scanf("%lld %lld %lld", &A, &B, &K);        printf("Case #%d: %lld\n",kase, Solve(B)-Solve(A-1));    }}

 HDU 2089 不要62    、 HDU 3555Bomb、      POJ 3252 (转换成二进制数)

经典熟悉板子的题了

HDU 3709 Balanced Number 

题意 : 求出 平衡数的个数, 类似杠杆, 利用 权值和为 0 , 枚举中心就好了

#include<bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 20;LL Num[20], Dp[20][20][1000][2];LL DFS(int L, int mid, int sum, bool e) {    if(L == -1) return sum ? 0 : 1;    if(!e && Dp[L][mid][sum][e]!= -1) return Dp[L][mid][sum][e];    LL ret = 0;    int u = e ? Num[L] : 9;    for(int i = 0; i <= u; ++i)    {        int tmp = (L-mid) * i + sum;        if(tmp >= 0)            ret += DFS(L-1, mid, tmp, e && (i==u));    }    return e ? ret : Dp[L][mid][sum][e] = ret;}LL Solve(LL N){    int L = 0;    while(N) {        Num[L++] = N % 10;        N /= 10;    }    ///    LL Ans = 0;    for(int i = 0; i < L; ++i)    {        memset(Dp,-1,sizeof(Dp));        Ans += DFS(L-1, i, 0, 1)-1;    }    return Ans + 1;}int main(){    int t;    LL A, B;    cin >> t;    while(t--)    {        cin >>A >> B;        cout << Solve(B)-Solve(A-1) <<endl;    }    return 0;}

 HDU 4507 

题目转换成求平方和;

需要数学公式先推导一下,

(a+b1)^2 + (a+b2)^2 + ... + (a+bn)^2 = n*a^2 + 2*a*(b1+b2+...+bn) + (b1^2 + b2^2 + ... + bn^2)

保存 num 个数 , sum 和, sum2 平方和三个状态,就可以快速求出值了。

#include<bits/stdc++.h>using namespace std;typedef long long LL;const LL MOD = 1e9 + 7;struct Node {      LL num, sum, sum2;Node(LL a = 0, LL b = 0, LL c = 0) :\num(a), sum(b), sum2(c) {} };bool Vis[30][10][10];Node Dp[30][10][10];LL Num[30];LL Pow[30];void INIT() {  memset(Vis, 0, sizeof(Vis));Pow[0] = 1; for(int i = 1 ; i < 20; ++i) Pow[i] = Pow[i-1]*10;}Node DFS(LL Len, LL Sum, LL Mod, bool e) {if(Len == -1) {if(Sum == 0 || Mod == 0) return Node(0,0,0);else return Node(1,0,0);}if(!e && Vis[Len][Sum][Mod]) return Dp[Len][Sum][Mod];int u = e ? Num[Len] : 9;Node ret, tmp;for(int i = 0; i <= u; ++i){if(i == 7) continue ;tmp = DFS(Len-1, (Sum+i) % 7, (Mod*10+i) % 7, e && (i==u));LL d = i * (Pow[Len] % MOD) % MOD;ret.num  = (tmp.num + ret.num) % MOD;ret.sum  = (d * tmp.num % MOD + tmp.sum + ret.sum) % MOD;ret.sum2 = (d*d%MOD*tmp.num%MOD + tmp.sum2 + ret.sum2 + 2 * d * tmp.sum % MOD) % MOD;}if(!e) {Vis[Len][Sum][Mod] = true;Dp[Len][Sum][Mod] = ret;}return ret;}LL Solve(LL N) {int L = 0;while(N) {Num[L++] = N % 10;N /= 10;}return DFS(L-1, 0, 0, 1).sum2;}int main(){INIT();int t;cin >> t;LL L, R;while(t--){cin >> L >> R;cout << (Solve(R) - Solve(L-1) + MOD) % MOD << endl;}return 0;}

 

0 0