专栏文章
题解:CF2053F Earnest Matrix Complement
CF2053F题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miqmi1fm
- 此快照首次捕获于
- 2025/12/04 07:13 3 个月前
- 此快照最后确认于
- 2025/12/04 07:13 3 个月前
本题最关键的结论是:每一行只会填一种数。考虑用调整法证明,设一行填了两种数,则考虑这两种数在上下两行中的出现次数,如果不一样则显然填一种可以更优;若一样则填一种等价。
于是可以设计最简单的 dp: 表示第 行的 全部填成 的最大贡献。此时把贡献如此拆:两行中都不是 的提前算出来;设上下两行中出现 的次数为 ,上一行和本行的问号个数为 ,则在 转移时加入 ;两行都是 的贡献在转移中记为 。转移为 。注意到可以提前处理出 做到 转移,时间复杂度 ,无法通过。
我们考虑维护整个 dp 数组的变化。注意到这玩意可以变成三个可以接受的操作:
-
全局加 。
-
全局对 取 。
-
对于所有有值的 ,单点加 。
按顺序做这三个操作,并实时维护 即可。注意到大部分操作是全局操作,我们设计一个标记 ,表示此时 。考虑三种操作,全局加 即让 都加 ;全局对 取 即令 对 取 。单点加的时候只需要求出当前的单点值,设做单点加后值为 ,注意到一定有 ,我们直接令 即可。 与这三种操作同时维护即可。时间复杂度 。
CPP#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define all(v) v.begin(),v.end()
#define pb push_back
#define REP(i,b,e) for(int i=(b);i<(int)(e);++i)
#define over(x) {cout<<(x)<<endl;return;}
int n,m,t;
int f[4000005],X,Y,g[1000005],c[1000005];
void Main() {
cin>>n>>m>>t;
vector<vector<int>>a(n, vector<int>(m));
vector<int>cnt(n);
REP(i,0,n){
cnt[i]=0;
vector<int>b;
REP(j,0,m){
int x;cin>>x;
if(x>0)b.pb(x-1);
else ++cnt[i];
}
reverse(all(b));REP(j,0,cnt[i])b.pb(-1);
reverse(all(b));a[i]=b;
}
if(n==1)over(0)
REP(i,0,t)f[i]=0;
int ans=0;
REP(i,0,n-1){
REP(j,cnt[i],m)++f[a[i][j]];
REP(j,cnt[i+1],m)ans+=f[a[i+1][j]];
REP(j,cnt[i],m)--f[a[i][j]];
}
REP(j,cnt[1],m)f[a[1][j]]+=cnt[0];
X=Y=0;int mx=0;
REP(i,0,t)mx=max(mx,f[i]);
REP(i,1,n){
vector<int>T;
REP(j,cnt[i-1],m)T.pb(a[i-1][j]);
if(i<n-1)REP(j,cnt[i+1],m)T.pb(a[i+1][j]);
for(auto j:T)c[j]=0;
for(auto j:T)++c[j];
int co=cnt[i]*cnt[i-1];
X+=co;Y=max(Y+co,mx);mx+=co;
for(auto j:T)if(c[j]){
f[j]=max(X+f[j],Y)+c[j]*cnt[i];
mx=max(mx,f[j]);
f[j]-=X;c[j]=0;
}
}
mx=0;
REP(j,0,t)mx=max(mx,max(f[j]+X,Y));
over(mx+ans)
}
void TC() {
int tc=1;
cin>>tc;
while(tc--){
Main();
cout.flush();
}
}
signed main() {
return cin.tie(0),cout.tie(0),ios::sync_with_stdio(0),TC(),0;
}
/*
1. CLEAR the arrays (ESPECIALLY multitests)
2. DELETE useless output
*/
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...