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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章