JZOJ 4314. 【NOIP2015模擬11.4】老司機
阿新 • • 發佈:2020-08-03
題目
思路
大意是構造一個數組使它做 \(01\) 揹包能表示出所有給定的數
那就暴力列舉每個位置填什麼
直到它能表示出所有給定的數
為了保證時間複雜度
我們考慮一個二進位制數 \(s\) 表示能構造出的數
\(s\) 的第 \(i\) 位為一就表示當前枚舉出的陣列能表示出 \(i\) 這個數
那麼假如一個數就是 \(s|(s << i)|(1<<i)\)
表示每位加上 \(i\) 的數是可以被表示的
小優化:當前填到這位可以構造出給定的所有數時,給當前位打個標記
以後做到這一位就可以直接 \(return\)
對應下面的 \(b\) 陣列
\(Code\)
#include<cstdio> using namespace std; typedef long long LL; const int N = 25; int n; LL a[N] , b[N] , c[N] , anss[N] , ans = 0x3f3f3f3f; inline void dfs(int x , LL s) { if (b[x - 1] || x - 1 >= ans) return; int fl = 0; for(register int i = 1; i <= n; i++) if (!(s & (1LL << a[i]))) { fl = 1; break; } if (!fl) { ans = x - 1 , b[x - 1] = 1; for(register int i = 1; i < x; i++) anss[i] = c[i]; return; } if (x > 6) return; for(register int i = c[x - 1]; i <= 50; i++) { c[x] = i; dfs(x + 1 , (s | (s << i)) | (1LL << i)); if (b[x]) return; } } int main() { freopen("driver.in" , "r" , stdin); freopen("driver.out" , "w" , stdout); scanf("%d" , &n); for(register int i = 1; i <= n; i++) scanf("%lld" , a + i); c[0] = 1; dfs(1 , 0); printf("%lld\n" , ans); for(register int i = 1; i <= ans; i++) printf("%lld " , anss[i]); }