20230717牛客多校赛(一)L

L - Three Permutations

题面
题意: 给定三个长度为 n n n的排列 a , b , c a,b,c a,b,c ( x , y , z ) (x,y,z) (x,y,z) , 最开始为 ( 1 , 1 , 1 ) (1,1,1) (1,1,1),每过一秒变为 ( a y , b Z , c x ) (a_y,b_Z,c_x) (ay,bZ,cx) q q q次询问求变成 ( x , , y , , z , ) (x^,,y^,,z^,) (x,,y,,z,)​的最短时间。

考试时看这样的连接关系以为会是一道图论,并且过的人非常少,就没有仔细想这道题,但其实这题是一道可做的数学题。

Solution:

性质:每过三秒 ( x , y , z ) (x,y,z) (x,y,z)会变为 ( a b c x , b c a y , c b a z ) (a_{b_{c_x}},b_{c_{a_{y}}},c_{b_{a_z}}) (abcx,bcay,cbaz),用复合关系表示为 ( a ∘ b ∘ c ( x ) , b ∘ c ∘ a ( y ) , c ∘ b ∘ a ( z ) ) (a\circ b\circ c(x),b\circ c\circ a(y),c\circ b\circ a(z)) (abc(x),bca(y),cba(z))

分别设这三个复合关系为 f a = a ∘ b ∘ c , f b = b ∘ c ∘ a , f c = c ∘ b ∘ a fa=a\circ b\circ c,fb=b\circ c\circ a,fc=c\circ b\circ a fa=abc,fb=bca,fc=cba 。即每三秒 ( x , y , z ) (x,y,z) (x,y,z)会变为 ( f a ( x ) , f b ( y ) , f c ( z ) ) (fa(x),fb(y),fc(z)) (fa(x),fb(y),fc(z))

我们考虑到在朴素情况下,数对 ( 1 , 1 , 1 ) (1,1,1) (1,1,1)不会同时第一次通过变换到达 ( x , y , z ) (x,y,z) (x,y,z),即三个位置上的数一次或多次分别到达了 x , y , z x,y,z x,y,z

因此我们可以线性计算出三个位置的数,通过 f a , f b , f c fa,fb,fc fa,fb,fc变换,第一次分别变换到 x , y , z x,y,z x,y,z的时间 α 1 , α 2 , α 3 \alpha_1,\alpha_2,\alpha_3 α1,α2,α3,三个位置从 1 1 1变换回 1 1 1的时间为 m 1 , m 2 , m 3 m_1,m_2,m_3 m1,m2,m3

则三个位置同时到达 ( x , y , z ) (x,y,z) (x,y,z)的时间 T T T满足 T ≡ α i ( m o d    m i ) T\equiv \alpha_i(\mod m_i) Tαi(modmi)

这是一个由三个同余方程构成的一元线性同余方程组,由于不保证模数为质数,我们用 e x c r t excrt excrt进行求解即可。

上面求解了从第 0 0 0秒开始进行的 f a , f b , f c fa,fb,fc fa,fb,fc变换,由于一次 f f f变换需要三秒,因此我们枚举起始时间为 0 , 1 , 2 0,1,2 0,1,2的情况,进行三次求解,即可求得所有解。

细节处理:

对于求解 α i \alpha_i αi ,标程中给了一个较好的处理,预处理出三个 d i s dis dis数组, d i s a / b / c i disa/b/c_i disa/b/ci代表从 1 1 1 i i i需要通过几次 f a / b / c fa/b/c fa/b/c变换得到,值为 − 1 -1 1即为不可到达。

因此求解 α i \alpha_i αi时只需要将 d i s a / b / c x / y / z disa/b/c_{x/y/z} disa/b/cx/y/z赋值给 α 1 / 2 / 3 \alpha_{1/2/3} α1/2/3即可。

对于无解情况有两种,第一种情况是通过 f a / b / c fa/b/c fa/b/c操作根本无法从 1 1 1变换到题目中给定的 x / y / z x/y/z x/y/z,即 d i s a / b / c x / y / z = − 1 disa/b/c_{x/y/z}=-1 disa/b/cx/y/z=1,此时无解。

第二种情况是 e x c r t excrt excrt的无解条件,即合并方程 x ≡ a i ( m o d m i ) x\equiv a_i\pmod {m_i} xai(modmi) x ≡ A ( m o d M ) x\equiv A\pmod M xA(modM)时, A A A a i a_i ai不满足 e x g c d exgcd exgcd的有解条件,即 g c d ( m i , M ) ∤ A − a i gcd(m_i,M)\nmid A-a_i gcd(mi,M)Aai

代码↓

#include
#define N 100100
using namespace std;
typedef long long ll;
const ll inf=1e18;
inline void read(ll &x){
    ll s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
ll n,q,x,y,z,flag;
ll a[N],b[N],c[N];
ll fa[N],fb[N],fc[N],disa[N],disb[N],disc[N];
ll ia[N],ib[N],ic[N];
ll mod[3],arr[3];
ll gcd(ll a, ll b){
    return b?gcd(b,a%b):a;
}
void exgcd(ll &x, ll &y, ll a, ll b){
    if(!b){x=1,y=0;return ;}
    exgcd(y,x,b,a%b);
    y-=a/b*x;
}
ll excrt(){
    ll A=arr[0],M=mod[0];
    for(ll i=1;i<=2;i++){
        ll p,q,a,b,c,g;
        a=M,b=mod[i],c=(arr[i]-A%b+b)%b,g=gcd(a,b);
        if(c%g)return inf;
        a/=g,b/=g,c/=g;
        exgcd(p,q,a,b);
        p=(p*c)%b;
        A+=M*p;M*=b;
        A=(A%M+M)%M;
    }
    return A;
}
ll solve(ll x, ll y , ll z){
    if(disa[x]==-1||disb[y]==-1||disc[z]==-1)return inf;
    arr[0]=disa[x],arr[1]=disb[y],arr[2]=disc[z];
    return excrt();
}
int main(){
    read(n);
    for(ll i=1;i<=n;i++)read(a[i]),ia[a[i]]=i;
    for(ll i=1;i<=n;i++)read(b[i]),ib[b[i]]=i;
    for(ll i=1;i<=n;i++)read(c[i]),ic[c[i]]=i;

    for(ll i=1;i<=n;i++){
        fa[i]=a[b[c[i]]];
        fb[i]=b[c[a[i]]];
        fc[i]=c[a[b[i]]];
    }

    memset(disa,-1,sizeof disa);
    memset(disb,-1,sizeof disb);
    memset(disc,-1,sizeof disc);
    for(ll i=1;disa[i]==-1;i=fa[i],mod[0]++)disa[i]=mod[0];
    for(ll i=1;disb[i]==-1;i=fb[i],mod[1]++)disb[i]=mod[1];
    for(ll i=1;disc[i]==-1;i=fc[i],mod[2]++)disc[i]=mod[2];

    read(q);
    for(ll i=1;i<=q;i++){
        read(x),read(y),read(z);
        ll ans=inf;
        for(ll j=0;j<=2;j++){
            ans=min(ans,solve(x,y,z)*3+j);
            ll t=y,p=x;
            x=ic[z],y=ia[p],z=ib[t];
        }
        if(ans==inf)puts("-1");
        else printf("%lld\n",ans);
    }
}

你可能感兴趣的:(考试,数论,集训,算法,c++,数论)