#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<set>
using namespace std;
inlineintread() {
int x = 0, f = 1; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -f; s = getchar(); }
while (s >= '0' && s <= '9') { x = x * 10 + s - '0'; s = getchar(); }
return x * f;
}
constint N = 50010, MLOGNLOGN = 20001000;
constint SIZE = 1e9 + 10;
int n, m;
int a[N];
multiset<int> s;
int cT, root[N];
structSegmentTree {int lc, rc;
int cnt;
longlong sum;
} t[MLOGNLOGN];
intNew() {
int p = ++ cT;
t[p].lc = t[p].rc = t[p].cnt = t[p].sum = 0;
return p;
}
voidinsert(int &p, int l, int r, int delta, int Cv, int Sv) {
if (!p) p = New();
t[p].cnt += Cv, t[p].sum += Sv;
if (l == r) return;
int mid = (l + r) >> 1;
if (delta <= mid)
insert(t[p].lc, l, mid, delta, Cv, Sv);
else
insert(t[p].rc, mid + 1, r, delta, Cv, Sv);
}
voidadd(int x, int delta, int Cv, int Sv) {
x = n - x + 1;
for (; x <= n; x += x & -x)
insert(root[x], 1, SIZE, delta, Cv, Sv);
}
vector<int> rt;
voidprework(int x) {
x = n - x + 1;
for (int i = rt.size() - 1; i >= 0; i --) rt.pop_back();
for (; x; x -= x & -x)
rt.push_back(root[x]);
}
longlongask(int l, int r, int k) {
if (l == r)
return1ll * k * l;
int mid = (l + r) >> 1;
int lcnt = 0;
longlong lsum = 0;
for (int i = 0; i < rt.size(); i ++)
lcnt += t[t[rt[i]].lc].cnt,
lsum += t[t[rt[i]].lc].sum;
if (k <= lcnt) {
for (int i = 0; i < rt.size(); i ++) rt[i] = t[rt[i]].lc;
return ask(l, mid, k);
} else {
for (int i = 0; i < rt.size(); i ++) rt[i] = t[rt[i]].rc;
return ask(mid + 1, r, k - lcnt) + lsum;
}
}
vector<int> recover;
voidround() {
int L = m;
int k = 0;
while (s.size() && (*s.begin()) <= L) {
int val = *s.begin();
recover.push_back(val);
s.erase(s.begin());
L -= val;
k ++;
}
for (int i = recover.size() - 1; i >= 0; i --) {
int val = recover[i];
s.insert(val);
recover.pop_back();
}
int res = m;
int last = 0;
for (int t = 1; t <= k; t ++) {
int l = last + 1, r = n;
while (l < r) {
int mid = (l + r + 1) >> 1;
prework(mid);
if (ask(1, SIZE, k - t + 1) <= res) l = mid; else r = mid - 1;
}
last = l;
res -= a[l];
s.erase(s.find(a[l]));
add(l, a[l], -1, -a[l]);
}
}
intmain() {
n = read(), m = read();
for (int i = 1; i <= n; i ++)
a[i] = read();
for (int i = 1; i <= n; i ++)
s.insert(a[i]);
for (int i = 1; i <= n; i ++)
add(i, a[i], 1, a[i]);
int ans = 0;
while (s.size())
round(), ans ++;
printf("%d\n", ans);
return0;
}
其中,第 i 个人对第 j 盘菜的评价为 ai,j。特别地,如果 ai,j=−1,则表示第 i 个人不喜欢第 j 盘菜。
若某个人在餐桌上看到了自己不喜欢的菜,那么他会被气走。
在确定了上菜方案的情况下。若第 i 个人在场,第 j 盘菜也在场,那么你就会获得 ai,j 的收益。
请确定一个上菜方案,使得你获得的收益最大化。
数据范围:1≤n≤20,1≤m≤106。
Solution
考虑枚举最后在场的人的集合 S,设在场的人的集合为 S 的时候的收益为 f(S)。
因为不容易直接求出所有 f 值,所以考虑构造一个辅助函数 g,满足:
f(S)=∑S⊆Tg(T)
记录 tj 表示不排斥第 j 盘菜的人的集合,对于第 i 个人对第 j 盘菜的评价 ai,j≥0:
g(tj)←+ai,jg(tj∖{i})←−ai,j
注意到如果第 j 道菜最终在场,那么 S 一定是 tj 的子集,即 S⊆tj。
为了保证贡献正确计算:
上述操作的第一步:计算所有不排斥第 j 盘菜的人的贡献。
上述操作的第二步:扣除所有不排斥第 j 盘菜,且不在场的人的贡献。
得到了 g 之后,dp 还原 f。
时间复杂度 O(2nn+nm)。
#include<cstdio>#include<cstring>#include<algorithm>
using namespace std;
inlineintread() {
int x = 0, f = 1; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -f; s = getchar(); }
while (s >= '0' && s <= '9') { x = x * 10 + s - '0'; s = getchar(); }
return x * f;
}
constint N = 21, M = 1001000;
int n, m;
int a[N][M];
int t[M];
longlong f[1 << N];
intmain() {
n = read(), m = read();
for (int i = 0; i < n; i ++)
for (int j = 1; j <= m; j ++)
a[i][j] = read();
for (int i = 0; i < n; i ++)
for (int j = 1; j <= m; j ++)
if (a[i][j] >= 0) t[j] |= (1 << i);
for (int i = 0; i < n; i ++)
for (int j = 1; j <= m; j ++)
if (a[i][j] >= 0) {
f[t[j]] += a[i][j];
f[t[j] ^ (1 << i)] -= a[i][j];
}
for (int i = 0; i < n; i ++)
for (int S = 0; S < (1 << n); S ++)
if (S & (1 << i)) f[S ^ (1 << i)] += f[S];
longlong ans = 0;
for (int S = 0; S < (1 << n); S ++)
ans = max(ans, f[S]);
printf("%lld\n", ans);
return0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探