模拟最大流
注意到模拟最大流实际上只在理论上与最大流有关,实际运用中都被看做是 DP。模拟网络流的难点实际上一般都包含发现这道题可以网络流做,因此需要一定的熟练度。
一般而言,模拟最大流都是先将原来一个看作很不可做的东西简化为网络流模型,然后根据最大流等于最小割,直接抛弃掉这个流的实际含义转而通过连通性来直接得到答案。这种 DP 的优势在于建模以后就不需要在意一些抽象的概念一类的东西而是只需要根据最小割的定义解答即可。
CF724E Goods transportation
最基本的模板题。
注意到根据题意建模以后就是一个裸的最大流模板。但是建出来的边数过多,考虑模拟网络流。
这个东西是所谓网络流中“链”的模型,也就是中间一串点分别与源点汇点相连然后这些点之间也有连边,将其排列成一列形成“链”的样式。
对于“链”上的一个点 \(i\),如果割掉其与汇点的边,那就可以先不管它,如果割掉的是其与源点的边,那我们就要将前面本身没有被割掉的点连向它的边全部割掉。注意到“链”上点之间的边的边权全部为 \(c\),因此我们只关心前面有多少个点没有被割掉。
于是我们设 \(f_{i,j}\) 表示第 \(i\) 个点,前面有 \(j\) 个点没有被割掉的最小割。根据上面的分析,显然有转移:
然后就做完了。时间复杂度 \(O(n^2)\)。可以发现完全不需要脑子只需要专心将连通性维护即可。
code
注意空间上需要将第一维压掉。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e4+7,inf=1e18+7;
int p[N],s[N],f[2][N],n,c;
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>c;for(int i=1;i<=n;i++)cin>>p[i];for(int i=1;i<=n;i++)cin>>s[i];
for(int i=1;i<=n;i++)f[0][i]=inf;
for(int i=1;i<=n;i++){
int u=i&1,v=u^1;
f[u][0]=f[v][0]+p[i];
for(int j=1;j<=i;j++){
f[u][j]=min(f[v][j-1]+s[i],f[v][j]+j*c+p[i]);
}
for(int j=i+1;j<=n;j++)f[u][j]=inf;
}
int ans=inf;for(int i=0;i<=n;i++)ans=min(ans,f[n&1][i]);
cout<<ans;return 0;
}
AT_abc332_g [ABC332G] Not Too Many Balls
略困难一点。联考上做出来的。实际上难度阈值都在 DP 上。对于这种一眼网络流建模的题目实际上思维含量没有想象中高。
这个就是网络流中另外一种常见的“二分图”模型。显然左右部点间的边数已经上天了,同时看上去 DP 是有前途的,因此直接上 DP。
考虑数据范围的不对称。发现实际上由于所有的左部点都向右部点有连边,因此右部点的割边的情况只与割掉的左部点的编号总数有关,与左部点如何割的无关。因此考虑对于每一种左部点的编号总数都预处理出右部点的割的情况。
然后直接暴力设 \(f_{i,j}\) 表示第 \(i\) 个点,前面没有割的点的编号和为 \(j\),然后直接暴力转移即可,不赘述。
code
但是在考场上想了半个多小时细节。有点怕想错了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+7;
int n,a[N],b[N],tmp[N];
void solve(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
int mx=sqrt(2*n),ans=0;
for(int w=1;w<=mx+1;w++){
for(int i=1;i<=n;i++)tmp[i]=0;
for(int i=1;i<=n;i++){
if(a[i]==w){
if(a[i]*a[i]-b[i]>=1&&a[i]*a[i]-b[i]<=n)ans+=tmp[a[i]*a[i]-b[i]];
tmp[b[i]]++;
}
}
for(int i=1;i<=n;i++){
if(a[i]>w&&a[i]*w-b[i]>=1&&a[i]*w-b[i]<=n)ans+=tmp[a[i]*w-b[i]];
}
}
cout<<ans<<'\n';return;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int T;cin>>T;while(T--)solve();
return 0;
}

浙公网安备 33010602011771号