[NOI 2020]制作菜品[背包dp]
观察数据范围可以发现 $m==n-1,m==n-2,m\geq n$ 是三个比较特殊的数据点,那么就找这三个点的规律
懒得写了,,,直接放 zhq 的 luogu blog 了:https://www.luogu.com.cn/blog/zhqwqsblog/post-6775-noi2020-zhi-zuo-cai-pin

然后就只剩下 $m == n - 2$ 了,还是懒得写了....

原来是记 $dp[i][j][k]$ 表示前 i 个选 j 个和为 k 的方案数,可以通过柿子转换
$\large\sum_{i=1}^xd_{r_i}=(x-1)k \rightarrow \sum_{i=1}^x(d_{r_i}-k)=-k$
这样 j 那一维就可以去掉了,这样就转变成了背包 dp(可行性01背包)

1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 #include <vector> 7 #include <cctype> 8 #include <set> 9 #include <bitset> 10 #include <queue> 11 #define inf 1000001 12 #define N 10001 13 #define INF 0x7fffffff 14 #define Inf (int)(5e6+10) 15 #define ll long long 16 #define pii std::pair <int, int> 17 #define mp(a, b) std::make_pair(a, b) 18 19 namespace chiaro { 20 21 template <class T> 22 inline void read(T& num) { 23 num = 0; register char c = getchar(), up = c; 24 while(!isdigit(c)) up = c, c = getchar(); 25 while(isdigit(c)) num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar(); 26 up == '-' ? num = -num : 0; 27 } 28 template <class T> 29 inline void read(T& a, T& b) {read(a); read(b);} 30 template <class T> 31 inline void read(T& a, T& b, T& c) {read(a); read(b); read(c);} 32 template <class T> 33 inline void read(T& a, T& b, T& c, T& d) {read(a); read(b); read(c); read(d);} 34 35 int n, m, k; 36 int g[Inf]; 37 int dl; 38 bool vis[inf]; 39 pii d[inf], d1[inf], d2[inf]; 40 int topd1, topd2; 41 std::bitset <Inf> f[2], tmp; 42 std::set <pii> s; 43 #define down(a) ((a) - dl) 44 45 inline void input() { 46 read(n, m, k); 47 for(int i = 1; i <= n; i++) { 48 read(d[i].first); 49 d[i].second = i; 50 } 51 return; 52 } 53 54 inline void solve1(pii* d, int n, int m) { // solve m >= n - 1 55 s.clear(); 56 for(int i = 1; i <= n; i++) s.insert(d[i]); 57 while(m > n - 1) { 58 auto it = s.end(); 59 auto p = *--it; 60 printf("%d %d\n", it->second, k); 61 s.erase(it); 62 if(p.first - k > 0) s.insert(mp(p.first - k, p.second)); 63 --m; 64 } 65 for(int i = 1; i <= m; i++) { 66 auto it = s.begin(); 67 if(it->first == k) { 68 printf("%d %d\n", it->second, k); 69 s.erase(it); 70 continue; 71 } 72 int sy = k - it->first; 73 printf("%d %d ", it->second, it->first); 74 s.erase(it); 75 it = s.end(); 76 auto p = *--it; 77 printf("%d %d\n", it->second, sy); 78 s.erase(it); 79 s.insert(mp(p.first - sy, p.second)); 80 } 81 return; 82 } 83 84 inline void clear() { 85 topd1 = topd2 = 0; 86 dl = 0; 87 f[0].reset(), f[1].reset(), tmp.reset(); 88 memset(g, 0, sizeof g); 89 memset(vis, 0, sizeof vis); 90 return; 91 } 92 93 inline void solve2 () { // m == n - 2 => (m == n - 1) & (m == n - 1) 94 clear(); 95 for(int i = 1; i <= n; i++) { 96 if(d[i].first < k) dl += (d[i].first - k); 97 } 98 bool now = 0; 99 f[now][down(0)] = 1; 100 for(auto i = 1; i <= n; i++) { 101 now = !now; 102 if(d[i].first - k >= 0) f[now] = f[!now] | (f[!now] << (d[i].first - k)); 103 else f[now] = f[!now] | (f[!now] >> (k - d[i].first)); 104 tmp = f[0] ^ f[1]; 105 for(int x = tmp._Find_first(); x != tmp.size(); x = tmp._Find_next(x)) g[x] = i; 106 if(f[now][down(-k)]) break; 107 } 108 if(f[now][down(-k)] == 0) return puts("-1"), void(); 109 int p = -k; 110 while(p) { 111 int x = g[down(p)]; 112 d1[++topd1] = d[x]; 113 vis[x] = 1; 114 p -= (d[x].first - k); 115 } 116 for(int i = 1; i <= n; i++) { 117 if(vis[i] == 0) d2[++topd2] = d[i]; 118 } 119 solve1(d1, topd1, topd1 - 1); 120 solve1(d2, topd2, topd2 - 1); 121 } 122 123 inline void solve() { 124 input(); 125 if(m >= n - 1) solve1(d, n, m); 126 else solve2(); 127 return; 128 } 129 130 inline void setting() { 131 freopen("dish.in", "r", stdin); 132 freopen("dish.out", "w", stdout); 133 } 134 135 inline int main () { 136 setting(); 137 int T; read(T); 138 while(T--) solve(); 139 return 0; 140 } 141 142 } 143 144 signed main () { 145 return chiaro::main(); 146 }

浙公网安备 33010602011771号