1.9模拟赛 T3题解

发布时间 2024-01-09 21:09:25作者: hubingshan

简要题意

求一个抽象函数,满足 \(∀? ∈ ℤ, ?(?) + ? = ?(2?(?) − ? + 1)\),给定 \(n\) 个点,使得 \(\sum |f(x_i)-y_i|\) 最小,输出最小值

思路

对这个函数进行一次迭代,可以得到 \(f(x+2C)=f(x)+2C\)
有了这个结论,我们就可以只对 \(x\in[0,2C)\) 进行讨论

这时我们考虑,如果有了一个 \(a\)\(f(a)\) ,我们还可以确定一个 \(b=2*f(a)-a+1\),所以 \(a+b=2*f(a)+1\),所以 \(a,b\) 的奇偶性不同,那现在我们就可以将 \(a,b\) 匹配的过程看作二分图匹配,匹配的代价就是 \(n\) 个点中和\(a,b\)同余的点的代价再算上一堆奇妙柿子的代价,最后跑二分图带权匹配即可

code

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 10005
#define CC 655
int n,C,top;
int x[N],y[N],q[N];
vector<int> num[CC];
int suan(int x){
	int ans=0;
	for(int i=1;i<=top;i++) ans+=abs(q[i]+x);
	return ans;
}
int cal(int a,int b){
	int X=a/2,Y=b/2;top=0;
	for(auto id:num[a]) q[++top]=X+Y+x[id]-a-y[id];
	for(auto id:num[b]) q[++top]=-X-Y+b-x[id]-C+y[id];
	sort(q+1,q+1+top);
	int mid=q[(top+1)/2]/C;
	return min(suan(-mid*C),min(suan(-(mid+1)*C),suan(-(mid-1)*C)));
}
struct AB{
	int a,b,c,v,n;
};
namespace FYL{
	int k=1,head,tail,S,T;
	const int inf=1e9;
	int h[CC],hh[CC],dis[CC],u[CC],vis[CC],q[CC*CC],sh[CC];
	AB d[CC*CC*3];
	void cun(int x,int y,int z,int w){
		d[++k]={x,y,z,w,h[x]},h[x]=k;
	}
	void link(int x,int y,int z,int w){
		cun(x,y,z,w),cun(y,x,0,-w);
	}
	void spfa(){
		memset(dis,9,sizeof(dis));
		memset(u,0,sizeof(u));
		q[head=tail=1]=S,dis[S]=0,u[S]=1;
		while(head<=tail){
			int x=q[head++];
			u[x]=0;
			for(int i=h[x];i;i=d[i].n){
				int y=d[i].b;
				if(!d[i].c||dis[x]+d[i].v>=dis[y]) continue;
				dis[y]=dis[x]+d[i].v;
				if(!u[y]) q[++tail]=y,u[y]=1;
			}
		}
	}
	priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > qq;
	void dij(){
		memset(dis,9,sizeof(dis));
		memset(u,0,sizeof(u));
		dis[S]=0,qq.push({0,S});
		while(!qq.empty()){
			int x=qq.top().second;qq.pop();
			if(u[x]) continue;
			u[x]=1;
			for(int i=h[x];i;i=d[i].n){
				int y=d[i].b;
				if(!d[i].c||dis[x]+d[i].v+sh[x]-sh[y]>=dis[y]) continue;
				dis[y]=dis[x]+d[i].v+sh[x]-sh[y],qq.push({dis[y],y});
			}
		}
	}
	int dfs(int x,int f){
		if(x==T) return f;
		int ff=f;vis[x]=1;
		for(int &i=h[x];i;i=d[i].n){
			int y=d[i].b;
			if(!d[i].c||dis[y]!=dis[x]+d[i].v+sh[x]-sh[y]||vis[y]) continue;
			int fl=dfs(y,min(f,d[i].c));
			if(fl) d[i].c-=fl,d[i^1].c+=fl,f-=fl;
			if(!f) break;
		}
		if(ff-f) vis[x]=0;
		return ff-f;
	}
	int dinic(){
		int ans1=0,ans2=0;
		memcpy(hh,h,sizeof(h));
		spfa();
		for(int i=0;i<=T;i++) sh[i]+=dis[i];
		while(1){
			memcpy(h,hh,sizeof(hh));
			dij();
			if(dis[T]==dis[T+1]) break;
			memset(vis,0,sizeof(vis));
			int fl=dfs(S,inf);
			if(!fl) break;
			ans1+=fl,ans2+=fl*(dis[T]+sh[T]);
			for(int i=0;i<=T;i++) sh[i]+=dis[i];
		}
		return ans2;
	}
}
signed main(){
	freopen("function.in","r",stdin);
	freopen("function.out","w",stdout);
	scanf("%lld%lld",&n,&C);
	FYL::S=2*C,FYL::T=FYL::S+1;
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&x[i],&y[i]);
		num[x[i]%(2*C)].push_back(i);
	}
	for(int i=0;i<2*C;i+=2){
		for(int j=1;j<2*C;j+=2) FYL::link(i,j,1,cal(i,j));
	}
	for(int i=0;i<2*C;i+=2) FYL::link(FYL::S,i,1,0);
	for(int i=1;i<2*C;i+=2) FYL::link(i,FYL::T,1,0);
	printf("%lld\n",FYL::dinic());
	return 0;
}