SPOJ BALNUM 位壓縮狀態 數字DP

2022-05-29 06:36:08 字數 1555 閱讀 4988

求區間[a,b]上的平衡數個數。平衡數是這樣的數:在數的各個位上,奇數數字出現偶數次,偶數數字出現奇數次。

很明顯我們需要記錄每一位出現的次數。分別記錄是不明智的,而我們又只需要記錄奇數次或者偶數次即可。所以我們可以用乙個<=1024的數state表示0~9這10個數字出現的次數奇偶性,當奇數出現偶數次則相應位為1,當偶數出現奇數次相應位為1,最後判斷是不是1023。但是這樣它的初試狀態不好確定。很明顯初始時我們需要把state賦值成1010101010,即682(0次算偶次)。但是如果某些偶數字從始至終都沒有出現,那麼那一位最終為0顯然不合理。我也沒有想到什麼更好的辦法,只能再加乙個1024的vis數表示0~9這10個數字是否出現過,但這樣空間不夠。後來想到乙個優化是我們不必記錄奇數是否出現過,因為它們初始就為1。所以可以把vis縮減到32,這樣空間就足夠了~問題邊迎刃而解。

[cpp]

#include #include #include #include #include #include #include #include #include #include #define mid(x,y) ((x+y)/2)

#define mem(a,b) memset(a,b,sizeof(a))

#define rep(i, begin, m) for (int i = begin; i < begin+m; i ++)

using namespace std;

typedef long long ll;

typedef vector vi;

typedef set seti;

typedef queue qi;

typedef stack si;

ll dp[20][1050][35][2];

vi num;

ll dfs(int pos, int state, int vis, bool flag, bool limit)

else if ((vis & (1 << (i/2))) != 0)

}return ok;

}if (!limit && ~dp[pos][state][vis][flag]) return dp[pos][state][vis][flag];

int end = limit?num[pos]:9;

ll res = 0;

for (int i = 0; i <= end; i ++)

else

}else

res += dfs(pos-1, next_state, next_vis, (!flag)&&i==0?flag:true, limit && (i==end));

}return limit?res:dp[pos][state][vis][flag] = res;

}ll cal(ll x)

int len = num.size();

return dfs(len-1, 682, 0, 0, 1);

}int main()

// for (int i = 100; i <= 1000; i ++)

return 0;

}[/cpp]

hdu1429(廣搜 狀態壓縮(位壓縮))

一開始用廣搜來做,超記憶體了,然後參照網上的資料,用位壓縮來做,頭一次做這種題,但個人感覺還是很好理解的,稍微看了一下就懂了,然後自己寫了個程式。思路 乙個有10把鑰匙,用10個位來表示,例如100 4 表示只有第三把鑰匙,1100 12 表示有第三四把鑰匙。如下 include include i...

hdu1429位運算狀態壓縮

第一次接觸位運算的狀態壓縮,這題本來我是用優先佇列寫的,用vector儲存鑰匙。本來以為會超時,沒想到是記憶體超限。無奈,找大神,發現正確姿勢是狀態壓縮。這題用來學 位運算的狀態壓縮是相當不錯,很好理解。題意是乙個人在乙個迷宮裡逃生,迷宮有鎖,有鑰匙,相應的鑰匙開相應的鎖。共有10種鎖。利用位運算就...

狀態壓縮DP之位運算總結

介紹 在進行dp題目分析時,針對狀態或子狀態可以抽象為 0 1 排列組合的題目時,將其 0 1 序列轉化為二進位制數,再而轉換為十進位制數,可以更加便捷的對其進行資料分析處理,減少因為混亂所造成的一些不必要的錯誤。魔鬼往往藏在細節之中。常用運算子 都是十進位制數在二進位制下所做的運算,返回十進位制的...