牛客练习赛60-D
传送门:https://ac.nowcoder.com/acm/contest/4853/D
题目大意:给你a,b,c,k。求一个线性方程组a*x+b*y+c*z=k。
分析:令p=a*x+b*y,则原题有解的条件变成p<=k,且(k-p)%c==0;那么我们就可以对p%c进行分类,显然,对于p%c来说,p肯定取一个较小的值比较好。这个时候,可以对于0-c-1这c个点分别连一些边。比如:i->(i+a)%c,代价为a,i->(a+b)%c,代价为b。这样就能对同一类,得到最小的代价。这样得到代价之后,跑一遍exgcd就可以得到答案了。
#include<bits/stdc++.h> #define all(x) x.begin(),x.end() #define fi first #define sd second #define lson (nd<<1) #define rson (nd+nd+1) #define PB push_back #define mid (l+r>>1) #define MP make_pair #define SZ(x) (int)x.size() using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; inline LL read(){ LL res=0, f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){res=res*10+ch-'0';ch=getchar();} return res*f; } const int MAXN = 200'005; const int MOD = 1000000007; void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;} int mulmod(int a, int b){return 1ll*a*b%MOD;} template<typename T> void chmin(T& a, T b){if(a>b)a=b;} template<typename T> void chmax(T& a, T b){if(b>a)a=b;} LL a, b, c, k; LL dd[MAXN]; LL ans[3]; int id; #define go(e,u) for(int e=head[u];e;e=Next[e]) LL to[MAXN<<1],Next[MAXN<<1],head[MAXN],dis[MAXN<<1],tol; void add_edge(int u,int v, LL val){ Next[++tol]=head[u];to[tol]=v;head[u]=tol;dis[tol]=val; } void dij(){ priority_queue<pair<LL, int>> q; for(int i=0;i<c;++i)dd[i]=1e18; q.push(MP(0,0)); dd[0]=0; while(!q.empty()){ int u=q.top().sd;q.pop(); go(e,u){ int v=to[e]; if(dd[v]>dd[u]+dis[e]){ dd[v]=dd[u]+dis[e]; q.push(MP(-dis[e],v)); } } } } LL exgcd(LL a, LL b, LL&x, LL& y){ if(!b){x=1;y=0;return a;} LL d=exgcd(b,a%b,x,y); swap(x,y); y-=a/b*x; return d; } int main(){ a=read();b=read();c=read();k=read(); for(int i=0;i<c;++i){ add_edge(i,(i+a)%c,a); add_edge(i,(i+b)%c,b); } dij(); for(int i=0;i<c;++i){ if(dd[i]<=k&&(k-dd[i])%c==0){ LL x, y, z, d; LL g=exgcd(a,b,x,y); x=((dd[i]/g)*x%(b/g)+(b/g))%(b/g); y=(dd[i]-a*x)/b; z=(k-a*x-b*y)/c; cout<<x<<" "<<y<<" "<<z; break; } } return 0; }