CDOJ 1136(数位DP)

题意&思路:

题意:求区间[1,n] 内满足i < j, 并且f(i) > f(j) 的数对数目?

学习了一波数位dp的一般写法,很爽。。。。

首先把原数字转化为二进制数,然后考虑dp[pos][diff][f1][f2][f3] 表示对于状态下的答案:
Pos:当前处于第pos位
Diff:f(i) - f(j)的值
F1: i与n的大小关系,1表示小于,0表示相等
F2: j与n的大小关系,1表示小于,0表示相等
F3: i与j的大小关系,1表示i < j

答案就是dfs(cnt - 1, 0, 0, 0, 0)

采用记忆化搜索的方式,所以访问的状态数等于 n * n * 8,不会超时,加上一点小小的剪枝,可以通过此题。

从高位往低位枚举,每次可以在i,j放的数字为0或1,同时需要考虑枚举的数不能超过n,因为题中涉及的是两个数之间的关系,所以自然要加入表示大小关系的状态,每次加上贡献就行了

代码:

#include <bits/stdc++.h>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int>  P;
const int N = 1750,MOD = 7+1e9;
char ss[N];
int cnt, bits[N];
int yu;
struct bign 
{
    int len;
    int num[N];

    bign() 
    {
        len = 0;
        memset(num, 0, sizeof(num));
    }

    bign(const char* number) 
    {
        *this = number;
    }

    void fix()
    {
        while(len && num[len-1] == 0) len--;
        if(len == 0) num[len++] = 0;
    }

    void operator = (char* number)
    {
        len = strlen(number);
        for(int i = 0;i < len;i ++)
            num[i] = number[len - i - 1] - '0';
        fix();
    }

    bign operator / (const int& b)
    {
        bign ans;
        yu = 0;
        for (int i = len - 1; i >= 0; i--) {
            yu = yu * 10 + num[i];
            ans.num[i] = yu / b;
            yu %= b;
        }
        ans.len = len;
        ans.fix();
        return ans;
    }
};

bign n;
int B, dp[N][N + N/2][2][2][2];
void update(int& x, int y)
{
    x += y;
    if(x >= MOD) x -= MOD;
}
int dfs(int pos, int diff, int f1, int f2, int f3)
{
    if(diff < 0 && (-diff) > (cnt/2)) return 0;
    int& now = dp[pos][diff + B][f1][f2][f3];
    if(now != -1) return now;
    now = 0;
    if(pos < 1) return now = (f3 && diff > 0);
    int x1 = 0, y1 = (f1 ? 1: bits[pos]);
    int x2 = 0, y2 = (f2 ? 1: bits[pos]);
    for(int i = x1;i <= y1;i ++)
    {
        for(int j = x2;j <= y2;j ++)
        {
            int newf3 = f3;
            if(newf3 == 0)
            {
                if(i < j) newf3 = 1;
                if(i > j) continue;
            }
            update(now, dfs(pos - 1, diff + i - j, f1|(i<y1), f2|(j<y2), newf3));
        }
    }
    return now;
}
void init()
{
    cnt = 1;
    n = ss;
    while(n.len != 1 || n.num[0] != 0)
    {
        n = (n / 2);
        bits[cnt ++] = yu;
    }
    B = cnt/2 + 1;
}
int main()
{
    scanf("%s", ss);
    init();
    memset(dp, -1, sizeof dp);
    printf("%d\n", dfs(cnt - 1, 0, 0, 0, 0));
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章