题解:P6775 [NOI2020] 制作菜品
m \ge n - 1
对于这种情况我们有一个显而易见的贪心,设数量最少的原料为第
首先先证明一下贪心的正确性,将
即假设
因为
就有
那么
因为
所以
与先前算的结果矛盾,所以假设不成立,在
m = n - 2
对于这种情况,我们容易发现如果还按贪心做法,最终可能会出现
注意到当 bitset 优化,就可以通过本题了。
题解还没通过,口胡一个证明吧。
首先这个充分性肉眼可见,所以只需要证明必要性。
假设
那么第一种情况
第二种情况,我们可以分出 轻喷)。
题解还没过,来聊聊时间复杂度吧挤牙膏写法。
首先,贪心就算写的再丑陋也不是时间复杂度的大头(我写的是
小细节:背包时有可能溢出,所以需要多开一点,并且初始化的值应该在中间。
CODE
#include<bits/stdc++.h>
using namespace std;
const int N = 505;
int n, m, k, d[N];
bool book[N];
bitset<5000004>bag[N], kk;
void dfs(int x, int y) {
if(!y) return;
else if(!bag[x + 1][2500000 + y]) book[x] = 1, dfs(x + 1, y - d[x]);
else dfs(x + 1, y);
}
struct node{ int id, d; };
bool operator <(const node & x, const node & y) {
if(x.d ^ y.d) return x.d < y.d;
else return x.id < y.id;
}
int main() {
//freopen("dish2.in", "r", stdin);
//freopen("1.out", "w", stdout);
int t;
scanf("%d", &t);
while(t--) {
//cout << t << endl << endl;
scanf("%d%d%d", &n, &m, &k);
for(int i = n; i; --i) scanf("%d", d + i);
if(m == n - 2) {
if(m == 3) {
puts("-1");
continue;
}
memset(book, 0, sizeof(book));
int dd[N];
for(int i = n; i; --i) {
dd[i] = d[i];
d[i] = k - d[i];
}
bag[n + 1][2500000] = 1, kk = 0, kk[2500000 + k] = 1;
//cout << kk << endl;
for(int i = n ; i; --i) {
bag[i] = bag[i + 1] | (d[i] >= 0 ? bag[i + 1] << d[i] : bag[i + 1] >> -d[i]);
//if(t == 5) cout << i << " " << bag[i][k] << endl;
}
if((bag[1] & kk) == 0) {
puts("-1");
continue;
}
dfs(1, k);
multiset<node> lc1, lc2;
for(int i = n; i; --i) {
if(book[i]) lc1.insert({n - i + 1, dd[i]});
else lc2.insert({n - i + 1, dd[i]});
}
while(!lc1.empty()) {
auto a = lc1.begin();
node aa = *a;
lc1.erase(a);
printf("%d %d", aa.id, aa.d);
if(aa.d < k) {
auto b = --lc1.end();
node bb = *b;
lc1.erase(b);
int bbb = k - aa.d;
printf(" %d %d", bb.id, bbb);
bb.d -= bbb;
if(bb.d) lc1.insert(bb);
}
putchar('\n');
} while(!lc2.empty()) {
auto a = lc2.begin();
node aa = *a;
lc2.erase(a);
printf("%d %d", aa.id, aa.d);
if(aa.d < k) {
auto b = --lc2.end();
node bb = *b;
lc2.erase(b);
int bbb = k - aa.d;
printf(" %d %d", bb.id, bbb);
bb.d -= bbb;
if(bb.d) lc2.insert(bb);
}
putchar('\n');
}
} else {
multiset<node> st;
for(int i = n; i; --i) st.insert({n - i + 1, d[i]});
while(!st.empty()) {
auto a = st.begin();
node aa = *a;
st.erase(a);
if(aa.d >= k) {
printf("%d %d", aa.id, k);
if(aa.d ^ k) {
aa.d -= k;
st.insert(aa);
}
} else {
auto b = --st.end();
node bb = *b;
st.erase(b);
int bbb = k - aa.d;
printf("%d %d %d %d", aa.id, aa.d, bb.id, bbb);
bb.d -= bbb;
if(bb.d) st.insert(bb);
}
putchar('\n');
}
}
}
return 0;
}