[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 } 

 

posted @ 2020-08-25 10:14  Chiaro  阅读(353)  评论(0)    收藏  举报