求區間[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 序列轉化為二進位制數,再而轉換為十進位制數,可以更加便捷的對其進行資料分析處理,減少因為混亂所造成的一些不必要的錯誤。魔鬼往往藏在細節之中。常用運算子 都是十進位制數在二進位制下所做的運算,返回十進位制的...