也就是不停講題寫題,沒講什麼實質性數字\(dp\),甚至只有後面三題有點點味道。
前面就是用到了數字的相關知識而已。
題目大意
多組資料,每組幾個操作\(opt\)與n個數,\(opt\)可能是\(and、xor、or\),求任意兩數\(opt\)運算後的最大值。
solution
顯然我們得分操作進行。
\(xor\)
當\(opt=xor\)時,你會發現這題十分熟悉。
the xor largest pair(隨手網上找的oj)
我們發現對於乙個0/1,我們需要找到和它相對的方向走。
比如當一位為1,我們要有最大代價,就應該找0與之形成貢獻。
然而對於找不到相對值的位置,沒有辦法,只能找相同數了。
直接乙個\(trie\)樹板子套上去就行了。
\(\mathrm\)
struct trie
}inline int ask(int x)
return ans;
}inline void clear()
} tr;
\(and\)
(直接念題解:)
從高位到低位貪心。畢竟and的限制性還是比較強的。
\(\mathrm\)
int vis[n] = {};
for(int i = 30; i >= 0; --i)
if(op <= 2)break;
if(cnt > 1)
}int ans = (1 << 30) - 1;
for(int i = 1; i <= n; ++i)
if(!vis[i])ans &= a[i];
\(or\)
or比較煩,因為限制少,答案難求,但我們依然從高位到低位貪心。
考慮每次都盡量取優。列舉某個數的不同位。
我們對於每個數,找到滿足最優條件(如上規則)的情況下,最小的乙個值,記為\(val\)。可以理解為:當某一位可選可不選的時候,讓它為0.
這麼搞出來的\(val\)一定是某個可行解的子集。
最後拼出的答案即為所求。
狀壓\(dp\)
\(\mathrm\)
memset(f, 0, sizeof(f));
for(int i = 1; i <= n; ++i)f[a[i]] = 1;
for(int i = (1 << 20) - 1; i >= 0; --i)
for(int j = 0; j <= 20; ++j)
f[i] |= f[i | (1 << j)];
code
完整**:
#include#define n 200010
#define int long long
int n, a[n] = {};
int k;
inline int read()
void write(int x)
//io
int f[1 << 21] = {};
struct trie
}inline int ask(int x)
return ans;
}inline void clear()
} tr;
//trie樹
void work()
; for(int i = 30; i >= 0; --i)
if(op <= 2)break;
if(cnt > 1)
}int ans = (1 << 30) - 1;
for(int i = 1; i <= n; ++i)
if(!vis[i])ans &= a[i];
write(ans);
putchar(10);
return ;
}if(k == 2)
if(k == 3)
write(sum);
putchar(10);
}}main()
題目大意
給定整數\(m,k\),求出正整數\(n\)使得\(n+1,n+2,...,2n\)中恰好有個\(m\)數在二進位制下恰好有\(k\)個\(1\)。有多組資料。
solution
這種題一上來就沒頭沒腦的,該怎麼做?
稍微手推幾組相鄰答案,嘗試尋找關聯。
感性理解:
而我們通過字首和的方式求解\(num(n)\)。
求\(s(x)\)
對於答案
\(\mathrm\)
#include #define int long long
using namespace std;
int n, m;
int read()
void write(int x)
int c[85][85];
inline int ask(int x)
return ans;
}inline bool check(int x)
int find()
return ans;
}void work(void)
if (n == 1 && m == 1)
int k1 = find();
++n;
int k = find();
write(k1);
putchar(32);
write(k - k1);
putchar(10);
return void();
}void pre(void)
main()
題目大意
乙個數字被稱為好數字需滿足下列條件:
①它有個\(2 \times n\)數字,\(n\)是正整數(允許有前導\(0\))。
②構成它的每個數字都在給定的數字集合\(s\)中。
③它前\(n\)位之和與後\(n\)位之和相等或者它奇數字之和與偶數字之和相等
例如,對於\(n=2\),\(s=\\),合法的好數字有\(8\)個:
\(1111\),\(1122\),\(1212\),\(1221\),\(2112\),\(2121\),\(2211\),\(2222\)。
已知,求合法的好數字個數\(mod\ 999983\)。
solution
我們可以通過一些操作得出一些奇怪結論。
然後就tm瞎算。
\(\mathrm\)
#include #define n 1010
#define mod 999983
#define int long long
using namespace std;
int n, m;
inline int add(int a, int b)
inline int del(int a, int b)
int read()
void write(int x)
int a[11] = {}, cnt = 0;
int f[n][n * 10] = {};
void work()
main()
後面的題都沒寫了
雖然真正的數字\(dp\)都在後面,但是我寫不動了。
鴿了吧。
學習筆記 訓練記錄 數字DP
數字dp,即對數字進行拆分,利用數字來轉移的一種dp,一般採用記憶化搜尋,或者是先預處理再進行轉移 乙個比較大略的思想就是可以對於給定的大數,進行按數字進行固定來轉移記錄答案 區間型別的,可以考慮字首和的思想,求 l,r 可以看做求 1,r 1,l 其實還有一種,是按照二進位制建一顆0,1樹來表示,...
HDU訓練記錄2 基礎數字dp
題目描述 傳送門題意 求0 n中含 49 的數的個數。題解狀態 f i j 表示i位數所有以j開頭的數中合法 不含 49 的數的個數。轉移 if j 4 k 9 f i j f i 1 k 列舉jk分別為i和i 1位數的開頭並且滿足條件。求解時用總數減去dp值。注意 這道題傳m 1的話有可能爆lon...
動態規劃學習系列 數字DP(初識)
第一次知道數字dp這東西,是在大二新手賽,那時有一道 cutting trees 的題目,現在來看就是水題一道,可以用多種方法水過,可惜當時愣是沒做出來,其他水題也沒做出來,於是被大一虐成翔。抱著學習的態度,我們再來看看這道題。多組詢問,每組詢問a和b,為 a,b 範圍內,有多少個數是由乙個上公升序...