社区讨论
WQS 二分做法是假的
P3354[IOI 2005] Riv 河流参与者 2已保存回复 2
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 2 条
- 当前快照
- 1 份
- 快照标识符
- @mhjs38op
- 此快照首次捕获于
- 2025/11/04 07:35 4 个月前
- 此快照最后确认于
- 2025/11/04 07:35 4 个月前
本题并没有凸性,虽然绝大多数时候凸性是成立的。所以,本题并不能够通过 WQS 二分求解。这篇题解 是有问题的。
用 排名最高的题解 改了一个测试凸性的代码,随便跑一两轮就能发现不满足凸性的情形:
CPP#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<random>
#include<chrono>
using namespace std;
#define int long long
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int head[501],nxt[1001],point[1001],weight[1001],sum[501],stack[1001],deep[1001];
long long f[111][111][111],g[111][111][111];
int n,tot,K,vi,di,sz;
void addedge(int x,int y,int cap){
tot++;nxt[tot]=head[x];head[x]=tot;point[tot]=y;weight[tot]=cap;
}
void dfs(int i){
stack[++sz]=i;
for(int tmp=head[i];tmp;tmp=nxt[tmp]){
int v=point[tmp];
deep[v]=deep[i]+weight[tmp];
dfs(v);
for(int j=1;j<=sz;j++)
for(int k=K;k>=0;k--){
f[i][stack[j]][k]+=f[v][stack[j]][0];
g[i][stack[j]][k]+=f[v][i][0];
for(int x=0;x<=k;x++){
f[i][stack[j]][k]=min(f[i][stack[j]][k],f[i][stack[j]][k-x]+f[v][stack[j]][x]);
g[i][stack[j]][k]=min(g[i][stack[j]][k],g[i][stack[j]][k-x]+f[v][i][x]);
}
}
}
//这里是将f和g合并了,因为之后就不在乎i有没有建伐木场,只关心i和i的子树建了多少。
for(int j=1;j<=sz;j++)
for(int k=0;k<=K;k++){
if(k>=1)
f[i][stack[j]][k]=min(f[i][stack[j]][k]+sum[i]*(deep[i]-deep[stack[j]]),g[i][stack[j]][k-1]);
//这里是g[i][stack[j]][k-1]的原因是:因为我们之前算g的时候,是假设i上有伐木场。而我们实际上没有把这个伐木场的数量加进去。所以合并前g[i][j][k]实际上代表的是g[i][j][k+1]
else
f[i][stack[j]][k]+=sum[i]*(deep[i]-deep[stack[j]]);
}
sz--;
}
signed main(){
n = 100;
K = 100;
for(int i=1;i<=n;i++){
sum[i] = rng() % 10000;
vi = rng() % i;
di = rng() % 10000;
addedge(vi,i,di);
}
dfs(0);
for (int k = 0; k <= K; ++k) {
printf("%lld %lld\n",f[0][0][k], (k > 0 && k < K ? 2 * f[0][0][k] - f[0][0][k-1] - f[0][0][k+1]: 0));
}
}
当然也可能是这串验证凸性的代码出问题了,欢迎讨论。
回复
共 2 条回复,欢迎继续交流。
正在加载回复...