HDU 5787 K-wolf Number(数位DP)

题目链接:点击打开链接

思路:

我们用dp[cur][a][b][c][d][p]表示当前到了第cur位,前四位分别是abcd并且当前是否已经小于给定的数的方案数。  我们分别算出L和R的dp值,  以及L是否符合要求, 做差并把多减的加上即可。  比赛时写的比较恶心, 不是很美观但是很直观。

细节参见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int seed = 131;
const ll INF64 = ll(1e18);
const int maxn = 11;
int n, m, v,cnt= 0, sum[maxn];
ll L, R, B[33], C[33], dp[19][maxn][maxn][maxn][maxn][2], vis[19][maxn][maxn][maxn][maxn][2];
int k, kase = 0, q, id;
ll dp1(int cur, int a, int b, int c, int d, int p) {
    ll& ans = dp[cur][a][b][c][d][p];
    if(cur == cnt) return 1LL;
    if(vis[cur][a][b][c][d][p] == kase) return ans;
    vis[cur][a][b][c][d][p] = kase;
    ans = 0;
    if(p) {
        for(int i = 0; i < 10; i++) {
            if(k == 2) {
                if(d == i) continue;
            }
            else if(k == 3) {
                if(c == i || d == i) continue;
            }
            else if(k == 4) {
                if(b == i || c == i || d == i) continue;
            }
            else {
                if(a == i || b == i || c == i || d == i) continue;
            }
            if(i == 0) {
                if(d == 10) ans += dp1(cur+1, a, b, c, d, p);
                else ans += dp1(cur+1, b, c, d, i, p);
            }
            else ans += dp1(cur+1, b, c, d, i, p);
        }
    }
    else {
        for(int i = 0; i < 10; i++) {
            if(k == 2) {
                if(d == i) continue;
            }
            else if(k == 3) {
                if(c == i || d == i) continue;
            }
            else if(k == 4) {
                if(b == i || c == i || d == i) continue;
            }
            else {
                if(a == i || b == i || c == i || d == i) continue;
            }
            if(i < B[cur]) {
                if(i == 0) {
                    if(d == 10) ans += dp1(cur+1, a, b, c,d, 1);
                    else ans += dp1(cur+1, b, c,d, i, 1);
                }
                else ans += dp1(cur+1, b, c,d, i, 1);
            }
            else if(i == B[cur]) {
                if(i == 0) {
                    if(d == 10) ans += dp1(cur + 1, a, b, c, d, p);
                    else ans += dp1(cur+1, b, c, d, i, p);
                }
                else ans += dp1(cur+1, b, c, d, i, p);
            }
        }
    }
    return ans;
}
bool ok() {
    for(int i = 0; i < cnt; i++) {
        for(int j = i-1; j >= max(0, i-(k-1)); j--) {
            if(B[j] == B[i]) return false;
        }
    }
    return true;
}
int main() {
    while(~scanf("%I64d%I64d%d", &L, &R, &k)) {
        ++kase;
        ll cur = R;
        int cc = 0; cnt = 0;
        while(cur) {
            C[cc++] = cur % 10;
            cur /= 10;
        }
        for(int i = cc-1; i >= 0; i--) {
            B[cnt++] = C[i];
        }
        ll ans1 = dp1(0, 10, 10, 10, 10, 0);
        cc = 0; cnt = 0;
        cur = L;
        while(cur) {
            C[cc++] = cur % 10;
            cur /= 10;
        }
        for(int i = cc-1; i >= 0; i--) B[cnt++] = C[i];
        ++kase;
        ll ans2 = dp1(0, 10, 10, 10, 10, 0);
        if(ok()) printf("%I64d\n", ans1 - ans2 + 1);
        else printf("%I64d\n", ans1 - ans2);
    }
    return 0;
}
时间: 2024-10-11 17:36:27

HDU 5787 K-wolf Number(数位DP)的相关文章

[hdu 4933]Miaomiao&#39;s Function 数位DP+大数

Miaomiao's Function Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 79    Accepted Submission(s): 18 Problem Description Firstly , Miaomiao define two functions f(x) , g(x): (K is the smallest

HDU 4352 XHXJ&#39;s LIS 数位DP + 状压

由LIS的nlogn解法 可以得出最后统计数组中数的个数即为LIS的长度 这样就可以状压了 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <c

HDU 4352 XHXJ&#39;s LIS 数位dp

题目链接:点击打开链接 题意: 一个数自身的最长子序列=每一位都是一个数字然后求的LIS 问区间内有多少个数 自身的最长子序列==k 思路: 因为自身的最长子序列至多=10,且由0~9组成,所以状压10个二进制表示0~9中哪些数字已经用过 dp[i][j] 表示长度为i的数字,最长子序列中出现的数字状态j的方法数.由于询问数=K,也存下来避免重复计算. #include <cstdio> #include <algorithm> #include <cstring> #

多校5 HDU5787 K-wolf Number 数位DP

1 // 多校5 HDU5787 K-wolf Number 数位DP 2 // dp[pos][a][b][c][d][f] 当前在pos,前四个数分别是a b c d 3 // f 用作标记,当现在枚举的数小于之前的数时,就不用判断i与dig[pos]的大小 4 // 整体来说就,按位往后移动,每次添加后形成的数都小于之前的数,并且相邻k位不一样,一直深搜到cnt位 5 // http://blog.csdn.net/weizhuwyzc000/article/details/5209769

HDU.4352.XHXJ&#39;s LIS(数位DP 状压 LIS)

题目链接 数位DP. 至于怎么求LIS,因为只有10个数,所以可以参照O(nlogn)求LIS的方法,状压记录状态. 每次加一个数和求LIS一样更新状态.最后状态中1的个数就是LIS的长度. //93MS 3004K #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define gc() getchar() typedef long long LL; c

hdu 5623 KK&#39;s Number(dp)

问题描述 我们可爱的KK有一个有趣的数学游戏:这个游戏需要两个人,有N\left(1\leq N\leq 5*{10}^{4} \right)N(1≤N≤5∗10?4??)个数,每次KK都会先拿数.每次可以拿任意多个数,直到NN个数被拿完.每次获得的得分为取的数中的最小值,KK和对手的策略都是尽可能使得自己的得分减去对手的得分更大.在这样的情况下,最终KK的得分减去对手的得分会是多少? 输入描述 第一行一个数T\left( 1\leq T\leq 10\right)T(1≤T≤10),表示数据组

hdu 2089 不要62 (数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 思路:用变量记录吉利数,和最高位为2的吉利数还有不是吉利数的个数... code: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[10][3]; //dp[i][j] ,i表示位数,j表示状态<pre name="code"

Hdu3079Balanced Number数位dp

枚举支点,然后就搞,记录之前的点的力矩和. #include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <s

SPOJ MYQ10 Mirror Number 数位dp&#39;

题目链接:点击打开链接 MYQ10 - Mirror Number A number is called a Mirror number if on lateral inversion, it gives the same number i.e it looks the same in a mirror. For example 101 is a mirror number while 100 is not. Given two numbers a and b, find the number

HDU 4588 Count The Carries 数位DP || 打表找规律

2013年南京邀请赛的铜牌题...做的很是伤心,另外有两个不太好想到的地方....a 可以等于零,另外a到b的累加和比较大,大约在2^70左右. 首先说一下解题思路. 首先统计出每一位的1的个数,然后统一进位. 设最低位为1,次低位为2,依次类推,ans[]表示这一位上有多少个1,那么有 sum += ans[i]/2,ans[i+1] += ans[i]/2; sum即为答案. 好了,现在问题转化成怎么求ans[]了. 打表查规律比较神奇,上图不说话. 打表的代码 #include <algo