ppt
首先考慮樸素做法。我們列舉 \(v\),檢查是否能存在 \(x\) 和 \(y\) 滿足 \(x\land y=v\)。
設dp狀態 \(f[i, 0/1,0/1,0/1,0/1]\) 表示當前考慮了前 \(i\) 位,是否存在一組 \(x\) 和 \(y\),滿足 \(x\land y=v\),\(x\lor y = t\),\(lx\leq x\leq rx\),\(ly\leq y\leq ry\)。後面那四組 \(0/1\) 表示 \(x\) 和 \(y\) 是否貼著上下界。
相信各位同學也都能看出來,這就是乙個簡單的數字dp!
從高位向低位轉移即可。
**片段:
inline bool solve() }}
}}}}
for (int lx = 0; lx <= 1; ++ lx) }}
}return false;
}
現在考慮如何優化這個演算法。
我們發現每次列舉 \(v\) 的過程太耗時。於是這啟發我們思考能不能直接計算出合法 \(v\) 的數量。
對於乙個確定的 \(v\) 來說,\(f\) 陣列肯定是確定的。但如果反過來,一套確定的 \(f\) 陣列可不一定對應著唯一的 \(v\)。所以,如果我們能對於某一套 \(f\) 陣列,直接算出有多少個 \(v\) 會算出這一套 \(f\) 並累加到答案中,計算效率就會提高不少。
現在就要祭出**:dp套dp!
設外層dp狀態 \(f[i,s]\) 表示當前考慮了前 \(i\) 位,\(f[i]\) 陣列的「情況」是 \(s\),所對應的 \(v\) 的數量。
其中 \(s\) 是乙個16位二進位制數。第一位代表 \(f[i,0,0,0,0]\) 的值,第二位代表 \(f[i,0,0,0,1]\) 的值,第三位代表 \(f[i,0,0,1,0]\) 的值……以此類推。
怎麼轉移呢?
首先列舉位數 \(i\)。其次列舉 \(s\)。再其次列舉 \(v\) 的第 \(i\) 位是0還是1。然後用我們剛才提出的小 \(f\) 的轉移方法,用 \(s\) 能轉移出 \(p\) 來。最後把 \(f[i,s]\) 累加到 \(f[i-1,p]\) 中即可。
具體實現見**。這份**不開o3過不去,原因是我每次直接把 \(f\) 陣列求出來了,如果直接使用位運算會快很多。
#include #include #include using namespace std;
#define filein(s) freopen(s".in", "r", stdin);
#define fileout(s) freopen(s".out", "w", stdout)
#define mem(s, v) memset(s, v, sizeof s)
inline long long read(void)
while (ch >= '0' && ch <= '9')
return f * x;
}const int maxn = 63;
bool f[2][2][2][2], g[2][2][2][2];
char t[maxn], lx[maxn], rx[maxn], ly[maxn], ry[maxn];
long long f[maxn][70000];
inline void change(long long x, char str)
}inline int call(int s, int i)
inline int get(int i, int st, int v) }}
}}
}cnt = 0;
int res = 0;
for (int lx = 0; lx <= 1; ++ lx) }}
}return res;
}int main() }}
long long ans = 0;
for (int s = 1; s < (1 << 16); ++ s) ans += f[1][s];
printf("%lld\n", ans);
return 0;
}
LOJ 6274 數字 數字dp
題目描述 nirobc 姐姐腦洞了兩個數字 和 它們滿足 且 nirobc 姐姐想知道 有多少種不同的取值,若有多組 的 值相同,則只算一次。其中 表示按位取或,c c 中寫作 pascal中寫作or 其中 表示按位取與,c c 中寫作 pascal中寫作and 輸入格式 一行,五個非負整數 輸出格...
題解 LOJ540遊戲
小l計畫進行n場遊戲,每場遊戲使用一張地圖,小 l 會同時使用三輛車在該地圖上完成遊戲。小 l 的賽車有三輛,分別用大寫字母 a b c 表示。地圖是一張無向簡單圖 沒有重邊或自環 每次他會在地圖中選擇不同的三個點 i,j,k滿足 i且兩兩之間均有邊。此時他會讓 a 從i到j,b 從j到k,c從k到...
題解 Loj2727舞會
n 個數,其中有 m 個位置的數是確定的,另外的數隨意排列。每次操作把最前面三個數取出,把它們的中位數取出來放到最後,然後刪掉這三個數。通過合適的排列,使最後留下來的數最大。首先這類有關中位數的問題,可以二分後轉化為操作 01 序列的問題。每次二分乙個有可能的答案 mid 把 mid 換成一,的數換...