10.26

一、array

    题目大意:给你一个序列n,然后再给你一个a,b,对于序列n中的每一个数,你都可以加减若干个a,b,使它变为0。问当序列所有的数都为0时,你耗费的最小代价(加减一次a或b代价为1)。如果无解请输出-1.很容易列出式子:ax+by=-xi。问题有解,当前仅当gcd(a,b)是-xi的因数。至于x,y我们可以用exgcd先求出一组(x,y)把他们乘上c/d求得一组特解。然后我们知道x,y的通解是(x+k*b/d,y-k*a/d)。我们要做的是,确定一个合适的k,是x,y改变之后他们绝对值之和最小。画出函数图像之后我们发现,如果a>b,那么我们让y尽可能接近0的时候答案最优。反之,a<b,我们让x尽可能接近0.所以我们保证a>b,如果不大于,swap一下。然后我们求出一个k,发现这个k有可能是不精准的,也就是下取整取得的,那我们再把他-1,+1分别求一下,比较出最小值,累加到ans就做完了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,a,b,x,y,c,d,temp,ans;
ll exgcd(ll a,ll b,ll &x,ll &y){
	if(b==0){
		x=1,y=0;return a;
	}
	ll d1=exgcd(b,a%b,x,y);
	ll tmp=x;x=y;y=tmp-a/b*y;
	return d1;
}
int main(){
	freopen("array.in","r",stdin);
	freopen("array.out","w",stdout);
	scanf("%lld%lld%lld",&n,&a,&b);
	if(a<b) swap(a,b);
	while(n--){
		scanf("%lld",&c);
		d=exgcd(a,b,x,y);
		if(((c%d)+d)%d){
			printf("-1\n");
			return 0;
		}
		x=x*c/d;
		y=y*c/d;
		temp=y*d/a;
		ll sum=1e12;
		for(ll i=temp-1;i<=temp+1;i++){
			ll tx=x+i*b/d;
			ll ty=y-i*a/d;
			ll siz=fabs(tx)+fabs(ty);
			sum=min(sum,siz);
		}
		ans+=sum;
	}
	printf("%lld\n",ans);
	return 0;
}

三、distance

    对于一个图,给你x个特殊点,求对于每一个特殊点xi,离他最近的特殊点到他的距离。

    当时觉得得关于每一个点跑一个最短路,复杂度是O(nlogn*p)的,只有10分。。。这道题其实挺好想的,关键在于你有没有绕过那个弯。假如这道题是求对于每一个点,所有特殊点到他距离最近的那个到它的距离呢?还是要跑p遍最短路吗?突然觉得这段时间自己思路有些僵化了,如果这样出的话,不就是一个多源点最短路径吗?直接把所有的特殊点仍队列里,跑一边spfa就可以了。当然这道题会比较复杂一些,不过我们可以先处理出对于每一个特殊点,离他距离最近的那个特殊点是什么。这个很好实现,只需要在更新某个点y的最优值的时候,把x的父亲同时也赋值给y就可以了。但是我们要怎么求这中间的距离呢?注意到,我们跑完spfa以后,关于所有的普通点,我们也求出了离他最近的特殊点是哪一个点。我们遍历一遍所有的边,如果边上的点x,y的父亲不一样,我们就可以用d[x]+d[y]+edge[i]来分别尝试更新ans[f[x]]和ans[f[y]]。当你遍历完所有的边时,你ans里存的一定是最短的了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10;
int n,m,tot,p,lef[maxn<<1],fa[maxn],te[maxn],ver[maxn<<1],Next[maxn<<1],lin[maxn],v[maxn];
ll edge[maxn<<1],d[maxn],ans[maxn];
queue<int> q;
void add(int x,int y,ll z){
	ver[++tot]=y;lef[tot]=x;Next[tot]=lin[x];lin[x]=tot;edge[tot]=z;
}
void spfa(){
	for(int i=1;i<=p;i++) q.push(te[i]),v[te[i]]=1;
	while(q.size()){
		int x=q.front();q.pop();
		v[x]=0;
		for(int i=lin[x];i;i=Next[i]){
			int y=ver[i];
			if(d[y]>d[x]+edge[i]){
				d[y]=d[x]+edge[i];
				fa[y]=fa[x];
				if(!v[y]){
					v[y]=1;
					q.push(y);
				}
			}
		}
	}
	for(int i=1;i<=2*m;i+=2){
		int x=lef[i],y=ver[i];ll z=edge[i];
		if(fa[x]!=fa[y]){
			ans[fa[x]]=min(ans[fa[x]],d[x]+d[y]+edge[i]);
			ans[fa[y]]=min(ans[fa[y]],d[x]+d[y]+edge[i]);
		}
	}
	for(int i=1;i<=p;i++) printf("%lld ",ans[te[i]]);
	cout<<endl;
}
int main(){
	freopen("distance.in","r",stdin);
	freopen("distance.out","w",stdout);
	scanf("%d%d%d",&n,&m,&p);
	memset(d,0x3f,sizeof(d));
	memset(ans,0x3f,sizeof(ans));
	for(int i=1;i<=p;i++){
		scanf("%d",&te[i]);
		d[te[i]]=0;fa[te[i]]=te[i];
	} 
	for(int i=1;i<=m;i++){
		int x,y;ll z;
		scanf("%d%d%lld",&x,&y,&z);
		add(x,y,z);add(y,x,z);
	}
	spfa();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39759315/article/details/83440826
今日推荐