1 条题解
-
0
- $\lfloor n\rfloor =n-\varepsilon,\varepsilon\in [0,1)$.
设路标的位置为 ,城市的位置为 。
那么 正确的 相当于限制了:
$$\exist \varepsilon_{i,j}\in [0,1):y_j-x_i-\varepsilon_{i,j}=d_{i,j}$$
的限制容易刻画:随机 次必定能取到一个在 最大合法路标集合 的元素 。实际这里常数取 比较稳。
现在钦定路标 在最大集合中,要找到 此时最大合法路标集合。
考虑判断这东西肯定是行找个参照减一下,列找个参照减一下。这样就把 消掉了。
行显然是找 减:$a_{i,j}=d_{i,j}-d_{u,j}=x_u-x_1-\varepsilon_{i,j}+\varepsilon_{u,j}$
列我们可以找最小值减,设第 行的最小值为 ,则有:
$$b_{i,j}=a_{i,j}-a_{i,w_i}=-\varepsilon_{i,j}+\varepsilon_{u,j}+\varepsilon_{i,w_i}-\varepsilon_{u,w_i}\ge 0$$
接下来要找到最大集合 ,使得 的取值互不矛盾,即存在 的填法满足 数组。
首先根据 得出 ,而 。
我们就可以丢弃所有存在 的行。接下来变形一下:
$$\varepsilon_{i,j}=\varepsilon_{u,j}-\varepsilon_{u,w_i}+\varepsilon_{i,w_i}-b_{i,j}$$单独考虑第 行,存在一个 使得对所有 上式都落在 的 充要条件 是:
$$\text{D}(\{\varepsilon_{u,j}-b_{i,j}\})<1 \\ \text{D}(S)=\max S-\min(S)$$因为 ,把行中的两类列分成 ,可以证明上面的条件等价于:
$$\max_{k\in S_0}\varepsilon_{u,k}\;<\;\min_{j\in S_1}\varepsilon_{u,j}$$也就是说,在某个给定的 大小顺序下,行 可行当且仅当所有 列都小于所有 列。
换句话说,记 ,相当于选出最多的 使得两两之间存在包含关系,否则顺序就矛盾了。
直接
bitset然后拓扑序遍历一遍,复杂度 。上述结论充分性显然,必要性就是具体构造合法的 。这里不赘述,感兴趣可以自己想想。
:::info[]
#include<bits/stdc++.h> #define LL long long #define all(x) x.begin(),x.end() #define bs basic_string<int> #define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout); using namespace std; mt19937 rnd(time(0)); const int N=1005,M=205; int n,m,d[N][M],a[N][M],L[N],pre[N]; bitset<M>f[N];bs ans; inline bs sol(int u) { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=d[i][j]-d[u][j]; bs g;int w; for(int i=1;i<=n;i++) { w=*min_element(a[i]+1,a[i]+1+m); bool o=1;f[i].reset(); for(int j=1;j<=m;j++) { a[i][j]-=w; if(a[i][j]>1){o=0;break;} f[i][j]=a[i][j]; } if(o) g+=i,L[i]=pre[i]=0; } sort(all(g),[](int x,int y){return f[x].count()<f[y].count();}); for(int i=0;i<g.size();i++) { int x=g[i]; for(int j=0;j<i;j++) { int y=g[j]; if((f[y]&f[x])==f[y]&&L[y]+1>L[x]) L[x]=L[y]+1,pre[x]=y; } }w=0; for(int i:g) if(L[i]>=L[w]) w=i; for(g.clear();w;w=pre[w]) g+=w;return g; } int main() { cin.tie(0)->sync_with_stdio(0);cout.tie(0);cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>d[i][j]; for(int i=1;i<=40;i++) { int x=rnd()%n+1;bs t=sol(x); if(t.size()>ans.size()) ans=t; } sort(all(ans),[](int x,int y){ for(int i=1;i<=m;i++) if(d[x][i]^d[y][i]) return d[x][i]>d[y][i]; return x<y; });cout<<ans.size()<<"\n"; for(int i:ans) cout<<i<<" "; return 0; }:::
- 1
信息
- ID
- 5758
- 时间
- 7000ms
- 内存
- 356MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者