To_Heart—题解——CF1473F
这里提供一种非常简单,而且贼有效的连边方式
首先因为靠后的点会被靠前的点限制,所以这是一道 最大闭合子图 的板题。
但是出题人卡了空间,当所有的 \(a_i\) 相同的时候,连边的复杂度是 \(n^2\) 的,会被卡掉。
我们考虑优化,因为 \(a_i \leq 100\) ,所以我们最多只需要连 100 条边就可以了,所以我们当 \(i\) 已经向 \(j\) 连边了,那么当 \(a_k=a_j,k\neq j\)的时候,我们就不需要由 \(i\) 向 \(k\) 连边了。这个可以直接用桶来实现。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
const int INF=0x3f3f3f3f;
struct zz{
int u,w,id;
};
vector<zz> v[200005];
struct Dinic{
int dist[200005],be[200005];
int s,t;
void Add(int x,int y,int z){
int idx=v[x].size(),idy=v[y].size();
v[x].push_back((zz){y,z,idy});
v[y].push_back((zz){x,0,idx});
}
bool BFS(){
bool f=0;memset(dist,-1,sizeof dist);
queue<int> q;q.push(s);
dist[s]=be[s]=0;
while(!q.empty()){
int x=q.front();q.pop();
int siz=v[x].size();
for(int i=0;i<siz;i++){
int y=v[x][i].u,w=v[x][i].w;
if(!w||dist[y]!=-1) continue;
q.push(y),be[y]=0,dist[y]=dist[x]+1;
if(y==t) f=1;
}
}
return f;
}
int DFS(int x,int sum){
if(x==t||!sum) return sum;
int siz=v[x].size(),ans=0;
for(int i=be[x];i<siz;i++){
int y=v[x][i].u,w=v[x][i].w,id=v[x][i].id;be[x]=i;
if(!w||dist[x]!=dist[y]-1) continue;
int now=DFS(y,min(sum-ans,w));
if(!now) dist[y]=0;
v[x][i].w-=now,v[y][id].w+=now,ans+=now;
}
return ans;
}
int dinic(){
int ans=0,now=0;
while(BFS()) while(now=DFS(s,INF)) ans+=now;
return ans;
}
}T;
int n,sum=0;
int a[10005],b[10005];
bool f[3005];
vector<int> V[100005];
signed main(){
cin>>n;T.s=0,T.t=n+1;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
for(int i=1;i<=n;i++) {
memset(f,0,sizeof f);
for(int j=i-1;j>=1;j--){
if(f[a[j]]) continue;
if(a[i]%a[j]==0) T.Add(i,j,INF),f[a[j]]=1;
}
}
for(int i=1;i<=n;i++){
if(b[i]>=0) T.Add(T.s,i,b[i]),sum+=b[i];
else T.Add(i,T.t,-b[i]);
}
printf("%lld\n",sum-T.dinic());
return 0;
}