Paşa və permutasiya#12294

Paşa və permutasiya (Həll təhlili)

Problem Müəllifi:

Tuncay Pashayev

Hazırlayan:

Hasan Saleh (MathModel)

Redaktə edən:

Hasan Saleh (MathModel)

Həll

Bizim ölçülü massivimiz, ölçülü massivimiz və bir tam ədəd var. massivinin bir permutasiya gözəl adlanır, əgər hər 1 \le i < m üçün b_{p_i} + b_{p_{i+1}} \equiv 0 \pmod{k} olarsa. Aşağıdakı implementasiyada yalnız mövqelərinin uzunluğunda bir zəncir formalaşdırdığını bilirik; bizə yalnız lazımdır, -nin faktiki indeksləri lazım deyil.

Biz N = 2\cdot 10^5-ə qədər 10^9+7 modulunda faktorialları və tərs faktorialları əvvəlcədən hesablayırıq və

P(n,r) = n P r = \frac{n!}{(n-r)!} \pmod{\text{MOD}}

şəklində müəyyən edirik, bu da fərqli elementdən element seçmək və sıralamaq üçün yolların sayıdır.

Hər test üçün -yı oxuyuruq və aşağıdakılara əsaslanaraq qururuq:

  • : -da dəqiq dəyər -in çoxluğu (təkrarlananları idarə etmək üçün),

  • : r = x \bmod k olan elementlərin sayı.

Sonra -ni oxuyuruq və onun məzmununu nəzərə almırıq, yalnız -ni saxlayırıq.

Əgər m = 1-dirsə, heç bir məhdudiyyət yoxdur, buna görə də multisetinin hər bir permutasiya gözəldir. Fərqli permutasiya sayısı

\frac{n!}{\prod_x (\text{cnt}[x]!)} \pmod{\text{MOD}},

şəklindədir, bu da fact[n] \cdot \prod_x invfact[\text{cnt}[x]] kimi həyata keçirilir.

İndi m \ge 2 olduğunu düşünək. Yalnız "xüsusi" mövqelər məhdudlaşdırılmışdır. Əgər zəncirdəki bir mövqenin modulunda qalıq -dirsə, zəncirdəki qonşu -in qalıq r_2 = (k - r) \bmod k olmalıdır, əks halda cəmi mod olmayacaq. Beləliklə, zəncirdəki qalıqlar tamamlayıcı cütlər (r, r_2) şəklində qurulur.

Tutaq ki,

o = \left\lfloor \frac{m+1}{2} \right\rfloor, \qquad e = \left\lfloor \frac{m}{2} \right\rfloor.

Əgər r \neq r_2-dirsə, o zaman zəncirdəki qalıqlar və r_2 arasında dəyişməlidir. İki naxış var: ilə başlamaq (onda qalıqlı mövqeyi və r_2 qalıqlı mövqeyi lazımdır) və ya r_2 ilə başlamaq (onda r_2 qalıqlı və qalıqlı mövqeyi lazımdır). Əgər \text{rem}[r] = c_0 və \text{rem}[r_2] = c_1 varsa və hər ikisi də varsa, məhdudlaşdırılmış mövqelərə fərqli elementləri təyin etmə yolları

P(c_0,o)\cdot P(c_1,e) \;+\; P(c_1,o)\cdot P(c_0,e).

Əgər r = r_2 (öz-özünə tamamlayıcı qalıq, məsələn, r=0 və ya r=k/2 cüt olduqda), onda bütün məhdudlaşdırılmış mövqelər yalnız qalıqdan istifadə etməlidir və əgər c_0 = \text{rem}[r] belə elementlər varsa, yolların sayı P(c_0,m)-dir.

Biz -dəki bütün qalıqlar -ni dövr edirik, r_2 = (k-r)\bmod k hesablayırıq və:

  • əgər r = r_2-dirsə, cur = P(c_0,m) istifadə edirik;

  • əgər r < r_2-dirsə və r_2 varsa, cur = P(c_0,o)P(c_1,e) + P(c_1,o)P(c_0,e) istifadə edirik;

  • əgər r > r_2-dirsə, keçirik (sırasız cüt \{r,r_2\} daha kiçik olan zaman idarə olunur).

Belə cütlər üçün yolları məhdudlaşdırılmış mövqələri doldurmaq üçün var. Qalan n-m mövqeləri sərbəstdir və qalan elementlərlə istənilən sırada doldurula bilər, bu da (n-m)! faktoru əlavə edir. Beləliklə, biz

ans \mathrel{+}= cur \cdot (n-m)!.

Bu nöqtəyə qədər, eyni dəyərin hər bir görünüşü fərqli etiketli obyekt kimi qəbul edilir. multisetinin fərqli permutasiyalarını saymaq üçün, biz hər bir fərqli dəyər üçün ilə bölürük, yəni invfact[\text{cnt}[x]] ilə vururuq. Bu, m=1 halındakı eyni düzəlişdir.

Ümumi mürəkkəblik \mathcal{O}(\sum n)-dir.

MOD=1000000007
MAX=200005

fact=[1]*MAX
invfact=[1]*MAX

for i in range(1,MAX):
    fact[i]=fact[i-1]*i%MOD
    invfact[i]=pow(fact[i],MOD-2,MOD)

def P(n,r):
    if r<0 or r>n:return 0
    return fact[n]*invfact[n-r]%MOD

def solve():
    n,m,k=map(int,input().split())
    rem={}
    cnt={}
    a=list(map(int,input().split()))
    for x in a:
        r=x%k
        rem[r]=rem.get(r,0)+1
        cnt[x]=cnt.get(x,0)+1
    input().split()
    if m==1:
        ans=fact[n]
        for c in cnt.values():
            ans=ans*invfact[c]%MOD
        print(ans)
        return
    o=(m+1)//2
    e=m//2
    ans=0
    for r,c0 in rem.items():
        r2=(k-r)%k
        if r==r2:
            cur=P(c0,m)
        elif r<r2:
            if r2 in rem:
                c1=rem[r2]
                cur=(P(c0,o)*P(c1,e)+P(c1,o)*P(c0,e))%MOD
            else:
                cur=0
        else:
            continue
        ans=(ans+cur*fact[n-m])%MOD
    for c in cnt.values():
        ans=ans*invfact[c]%MOD
    print(ans)


for _ in range(int(input())):
    solve()