codeforces516E Drazil and His Happy Friends

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yzyyylx/article/details/88061637

题面

题意

有n个男孩,m个女孩,他们中有些人高兴,其他人不高兴,第 i i 天,第 i m o d    n i\mod n 个男孩会和第 i m o d    m i\mod m 个女孩约会,若两人中有一个人高兴,则两个人都会高兴,则至少几天后,所有人都会高兴。

做法

首先可以将所有人根据模 gcd ( n , m ) \gcd(n,m) 值分成 gcd ( n , m ) \gcd(n,m) 组,不难发现如果某一组中一个高兴的人都没有,必然无解,然后分别计算每组的答案取最大值即可,现在考虑如何计算每组的答案。
可以发现如果第i个男孩高兴了,那么在m时刻后,第 ( i + m ) m o d    n (i+m)\mod n 个男孩也会高兴。同理,如果第i个女孩高兴,在n时刻后,第 ( i + n ) m o d    m (i+n)\mod m 个女孩也会高兴。同样,如果第x个女孩初始高兴,那么第 x m o d    n x\mod n 个男孩在第x时刻就会高兴,在m时刻后,第 ( x + m ) m o d    n (x+m)\mod n 个男孩也会高兴。我们可以只考虑男孩对男孩的贡献,女孩对女孩的贡献,和前 max ( n , m ) \max(n,m) 时刻中男女孩之间的贡献。可以发现这三种贡献包含了所有贡献。
对这三种贡献考虑建图,用最短路求解,第i个男孩向第 ( i + m ) m o d    n (i+m)\mod n 个男孩连权值为m的边,女孩同理,新建源点向初始高兴的点连权值为该点编号的边,若第i个男孩初始高兴,则向第 i m o d    m i\mod m 个女孩连权值为0的边,女孩的连边同理,可以发现这张图从源点出发,到初始不高兴的人所对应的点的最短路的最大值即为答案。
现在考虑去掉一些点,可以发现对于所有初始高兴的男孩u(现在若相同编号的女孩初始高兴,也把该男孩看作初始高兴),最短路的最大值只有可能是点 ( u m ) m o d    n (u-m)\mod n ,也就是向初始高兴的男孩连边的男孩,因为男孩间的连边恰好构成了一个环,女孩也同理,所以可以只保留这些点和初始高兴的人对应的点,这样点数就只于初始高兴的人数有关了。
对于求男孩u到v的距离,可以发现就等价于求满足方程 x m + k n = v u x*m+k*n=v-u 的最小非负整数x,可以先用扩展欧几里得算法求出方程 x m + y n = 1 x*m+y*n=1 的一组解,然后就能快速求两男孩或两女孩间的距离。

代码

#include<bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N 800100
using namespace std;

ll n,m,x,y,g,ans,tt,bb,dd,st,first[N],dn[N],len[N],d[N];
bool in[N],ok[N];
struct Bn
{
    ll to,next,quan;
}bn[N<<1];
queue<ll>que;
vector<ll>a[N],b[N];
unordered_map<ll,ll>mm[2],use;

ll eg(ll u,ll v,ll &x,ll &y)
{
    if(!v)
    {
		x=1,y=0;
		return u;
    }
    ll res=eg(v,u%v,x,y);
    x=x-u/v*y,swap(x,y);
    return res;
}

inline void add(ll u,ll v,ll w)
{
    bb++;
    bn[bb].to=v;
    bn[bb].next=first[u];
    bn[bb].quan=w;
    first[u]=bb;
}

inline ll disa(ll u,ll v){return y*(((v-u)%n+n)%n/g)%(n/g)*m;}
inline ll disb(ll u,ll v){return x*(((v-u)%m+m)%m/g)%(m/g)*n;}
inline bool cmpa(ll u,ll v){return disa(st,u)<disa(st,v);}
inline bool cmpb(ll u,ll v){return disb(st,u)<disb(st,v);}
inline ll zh(bool u,ll v){if(mm[u].count(v)) return mm[u][v];len[++tt]=v;return mm[u][v]=tt;}

inline ll calc(ll u)
{
    sort(a[u].begin(),a[u].end()),sort(b[u].begin(),b[u].end());
    tt=1,bb=0,mm[0].clear(),mm[1].clear();
    ll i,j,p,q,t,res=0;
    dd=0,use.clear();
    for(i=0;i<a[u].size();i++) dn[++dd]=a[u][i],add(zh(0,a[u][i]),zh(1,a[u][i]%m),0),use[a[u][i]]=1,ok[zh(0,a[u][i])]=1;
    for(i=0;i<b[u].size();i++) if(!use.count(b[u][i]%n)) dn[++dd]=b[u][i],use[b[u][i]%n]=1;
    st=dn[1],sort(dn+1,dn+dd+1,cmpa);
    for(i=1;i<=dd;i++)
    {
		p=zh(0,dn[i]%n),q=zh(0,dn[i%dd+1]%n);
		add(1,p,dn[i]);
		add(p,q,disa(dn[i]%n,dn[i%dd+1]%n));
		q=zh(0,((dn[i%dd+1]-m)%n+n)%n);
		if(p!=q) add(p,q,disa(dn[i],((dn[i%dd+1]-m)%n+n)%n));
    }

    dd=0,use.clear();
    for(i=0;i<b[u].size();i++) dn[++dd]=b[u][i],add(zh(1,b[u][i]),zh(0,b[u][i]%n),0),use[b[u][i]]=1,ok[zh(1,b[u][i])]=1;
    for(i=0;i<a[u].size();i++) if(!use.count(a[u][i]%m)) dn[++dd]=a[u][i],use[a[u][i]%m]=1;
    st=dn[1],sort(dn+1,dn+dd+1,cmpb);
    for(i=1;i<=dd;i++)
    {
		p=zh(1,dn[i]%m),q=zh(1,dn[i%dd+1]%m);
		add(1,p,dn[i]);
		add(p,q,disb(dn[i]%m,dn[i%dd+1]%m));
		q=zh(1,((dn[i%dd+1]-n)%m+m)%m);
		if(p!=q) add(p,q,disb(dn[i],((dn[i%dd+1]-n)%m+m)%m));
    }

    d[1]=0;
    que.push(1);
    for(;!que.empty();)
    {
		q=que.front();
		que.pop();
		in[q]=0;
		for(p=first[q];p!=-1;p=bn[p].next)
		{
		    t=bn[p].to;
		    if(d[t]<=d[q]+bn[p].quan) continue;
		    d[t]=d[q]+bn[p].quan;
		    if(!in[t])
		    {
				in[t]=1;
				que.push(t);
		    }
		}
    }
    for(i=1;i<=tt;i++) if(!ok[i]) res=max(res,d[i]);
    for(i=1;i<=tt;i++) first[i]=-1,d[i]=INF,ok[i]=0;
    return res;
}

int main()
{
    memset(first,-1,sizeof(first));
    memset(d,0x3f,sizeof(d));
    ll i,j,p,q;
    cin>>n>>m;
    g=eg(n,m,x,y);
    if(g>200000)
    {
		puts("-1");
		return 0;
    }
    p=m/g,q=n/g;
    x=(x%p+p)%p;
    y=(y%q+q)%q;
    cin>>p;for(i=1;i<=p;i++) scanf("%lld",&q),a[q%g].push_back(q);
    cin>>p;for(i=1;i<=p;i++) scanf("%lld",&q),b[q%g].push_back(q);
    for(i=0;i<g;i++)
    {
		if(!a[i].size() && !b[i].size())
		{
		    puts("-1");
		    return 0;
		}
		ans=max(ans,calc(i));
    }
    cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/yzyyylx/article/details/88061637
今日推荐