令$d=gcd(n,m)$,存在$x$和$y$使得$xn+i=ym+j$的充要条件是$iequiv j(mod d)$,因此将$xd+i$(其中$0le i<d$)作为一组,共有$d$组,根据上述结论任意两组之间相互独立
若一组中没有快乐的人,由于独立性必然无解,即有解需要$且forall 0le i<d,exists tin xcup y且tequiv i(mod d)$,必要条件为$dle b+g$(以下记$b+g$为$N$来表示复杂度),因此可以对每一组分别求出天数$t_{i}$,则有$ans=max_{0le i<d}t_{i}d+i$(以下子问题中仍用$ans$来表示$t_{i}$)
对于子问题,显然有$gcd(n,m)=1$,再不妨假设$nge m$($n<m$交换即可),则若第$tge m$天所有男生都快乐,所有女生必然快乐
证明:对于前$m$天,对$m$取模构成完全剩余系,即每个女生恰好出现一次;对$n$取模构成剩余系,即男生各不相同
反证法,若某个女生不快乐,其和其对应的男生必然都不快乐,而到第$t$天那个男生仍然不快乐,不符合假设
由此,$ans$即为最后一个快乐的男生的时间或$ans<m$,后者特判一下即可
若第$t$天且女生$i$(其中$iequiv t(mod m)$)快乐,则男生$j$(其中$jequiv t(mod n)$)必然快乐,而类似的可以证明女生$i$快乐等价于男生$(j+n-m) mod n$快乐的,因此不妨看作:若第$t$天且男生$(i+n-m) mod n$快乐,则男生$i$必然快乐
还需要考虑初始状态,若初始女生$i$快乐且男生$i$不快乐,可以看作男生$i$快乐(以下就用$S=xcup y$来表示初始快乐的集合)
考虑建图:将$((i+n-m) mod n,i)$连边,由于$gcd(n,m)=1$,因此这必然是一个大小为$n$的环,每一个初始的点影响其后面的若干个数(直到下一个初始的点),即$ans=max_{tin S}(t+mcdot min_{k>0,(t+km) mod nin S}(k-1))$
考虑后面这个$min$:若枚举最终结果$t'=(t+km) mod n$,即求同余方程$t+kmequiv t'(mod n)$的最小正整数解:用exgcd求出$kmequiv 1(mod n)$的最小正整数解$k'$(预处理),原方程最小正整数解即为$(k'(t'-t+n)+n-1) mod n+1$
先特判$t'=t$的情况,当$|S|=1$时才会选择这一个,因此解即$k'(t'-t+n) mod n=(k't'-k't+k'n) mod n$,那么将所有数按照$kt' mod n$排序并找到之后的那个数即可,复杂度$o(log_{2}n+Nlog_{2}N)$
View Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define ll long long 5 int n,m,d,kk,b[N],g[N],vb[N],vg[N],v[N<<1]; 6 ll ans; 7 bool cmp(int x,int y){ 8 return (x%d<y%d)||(x%d==y%d)&&(x<y); 9 } 10 int exgcd(int x,int y,int &a,int &b){ 11 if (!y){ 12 a=1; 13 b=0; 14 return x; 15 } 16 int g=exgcd(y,x%y,b,a); 17 b-=(x/y)*a; 18 return g; 19 } 20 ll calc(){ 21 bool flag=(n<=vb[0]+vg[0]); 22 ll ans=-1; 23 if (flag){ 24 for(int i=0,j=1,k=1;i<n;i++){ 25 if (((j>vb[0])||(vb[j]!=i))&&((k>vg[0])||(vg[k]!=i))){ 26 flag=0; 27 break; 28 } 29 if ((i<m)&&((j>vb[0])||(vb[j]!=i)||(k>vg[0])||(vg[k]!=i)))ans=i; 30 if ((j<=vb[0])&&(vb[j]==i))j++; 31 if ((k<=vg[0])&&(vg[k]==i))k++; 32 } 33 if (flag)return ans; 34 ans=0; 35 } 36 v[0]=0; 37 for(int i=1;i<=vb[0];i++)v[++v[0]]=1LL*vb[i]*kk%n; 38 for(int i=1;i<=vg[0];i++)v[++v[0]]=1LL*vg[i]*kk%n; 39 sort(v+1,v+v[0]+1); 40 if (v[1]==v[v[0]])return 1LL*v[1]*m%n+1LL*(n-1)*m; 41 ans=1LL*v[v[0]]*m%n+((v[1]-v[v[0]]+1LL*kk*n)%n-1)*m; 42 for(int i=1;i<v[0];i++) 43 if (v[i]!=v[i+1])ans=max(ans,1LL*v[i]*m%n+((v[i+1]-v[i])%n-1LL)*m); 44 return ans; 45 } 46 int main(){ 47 scanf("%d%d",&n,&m); 48 d=exgcd(n,m,b[0],g[0]); 49 n/=d; 50 m/=d; 51 if (n>m)kk=(g[0]%n+n)%n; 52 else kk=(b[0]%m+m)%m; 53 scanf("%d",&b[0]); 54 for(int i=1;i<=b[0];i++)scanf("%d",&b[i]); 55 scanf("%d",&g[0]); 56 for(int i=1;i<=g[0];i++)scanf("%d",&g[i]); 57 if (d>b[0]+g[0]){ 58 printf("-1"); 59 return 0; 60 } 61 sort(b+1,b+b[0]+1,cmp); 62 sort(g+1,g+g[0]+1,cmp); 63 if (n<m)swap(n,m); 64 for(int i=0,j=1,k=1;i<d;i++){ 65 vb[0]=vg[0]=0; 66 while ((j<=b[0])&&(b[j]%d==i))vb[++vb[0]]=b[j++]/d; 67 while ((k<=g[0])&&(g[k]%d==i))vg[++vg[0]]=g[k++]/d; 68 if ((!vb[0])&&(!vg[0])){ 69 printf("-1"); 70 return 0; 71 } 72 ans=max(ans,calc()*d+i); 73 } 74 printf("%lld",ans); 75 }