码迷,mamicode.com
首页 > 其他好文 > 详细

数位DP

时间:2015-11-26 22:43:01      阅读:267      评论:0      收藏:0      [点我收藏+]

标签:

 

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;
}

 

数位DP

标签:

原文地址:http://www.cnblogs.com/aoxuets/p/4998887.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!