[cf516E]Drazil and His Happy Friends

令$d=\gcd(n,m)$,存在$x$和$y$使得$xn+i=ym+j$的充要条件是$i\equiv j(mod \ d)$,因此将$xd+i$(其中$0\le i<d$)作为一组,共有$d$组,根据上述结论任意两组之间相互独立
若一组中没有快乐的人,由于独立性必然无解,即有解需要$且\forall 0\le i<d,\exists t\in x\cup y且t\equiv i(mod\ d)$,必要条件为$d\le b+g$(以下记$b+g$为$N$来表示复杂度),因此可以对每一组分别求出天数$t_{i}$,则有$ans=\max_{0\le i<d}t_{i}d+i$(以下子问题中仍用$ans$来表示$t_{i}$)
对于子问题,显然有$\gcd(n,m)=1$,再不妨假设$n\ge m$($n<m$交换即可),则若第$t\ge m$天所有男生都快乐,所有女生必然快乐
证明:对于前$m$天,对$m$取模构成完全剩余系,即每个女生恰好出现一次;对$n$取模构成剩余系,即男生各不相同
反证法,若某个女生不快乐,其和其对应的男生必然都不快乐,而到第$t$天那个男生仍然不快乐,不符合假设
由此,$ans$即为最后一个快乐的男生的时间或$ans<m$,后者特判一下即可
若第$t$天且女生$i$(其中$i\equiv t(mod\ m)$)快乐,则男生$j$(其中$j\equiv t(mod\ n)$)必然快乐,而类似的可以证明女生$i$快乐等价于男生$(j+n-m)\ mod\ n$快乐的,因此不妨看作:若第$t$天且男生$(i+n-m)\ mod\ n$快乐,则男生$i$必然快乐
还需要考虑初始状态,若初始女生$i$快乐且男生$i$不快乐,可以看作男生$i$快乐(以下就用$S=x\cup y$来表示初始快乐的集合)
考虑建图:将$((i+n-m)\ mod\ n,i)$连边,由于$\gcd(n,m)=1$,因此这必然是一个大小为$n$的环,每一个初始的点影响其后面的若干个数(直到下一个初始的点),即$ans=\max_{t\in S}(t+m\cdot \min_{k>0,(t+km)\ mod\ n\in S}(k-1))$
考虑后面这个$\min$:若枚举最终结果$t'=(t+km)\ mod\ n$,即求同余方程$t+km\equiv t'(mod\ n)$的最小正整数解:用exgcd求出$km\equiv 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+N\log_{2}N)$
 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 }
View Code

 

posted @ 2020-08-27 09:20  PYWBKTDA  阅读(150)  评论(0编辑  收藏  举报