Pasha and permutations#12294

Pasha and permutations (Editorial)

Problem Author:

Tuncay Pashayev

Prepared by:

Hasan Saleh (MathModel)

Edited by:

Hasan Saleh (MathModel)

Solution

We have an array of size , an array of size and an integer . A rearrangement of is called beautiful if for every 1 \le i < m we have b_{p_i} + b_{p_{i+1}} \equiv 0 \pmod{k}. In the implementation below we use only the fact that the positions form a chain of length ; we only need , not the actual indices of .

We precompute factorials and inverse factorials modulo 10^9+7 up to N = 2\cdot 10^5, and define

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

as the number of ways to choose and order elements from distinct ones.

For each test we read and build:

  • : multiplicity of the exact value in (to handle duplicates),

  • : number of elements with remainder r = x \bmod k.

Then we read and ignore its content, we only keep .

If m = 1, there are no constraints at all, so every rearrangement of the multiset is beautiful. The number of distinct permutations is

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

implemented as fact[n] \cdot \prod_x invfact[\text{cnt}[x]].

Now assume m \ge 2. Only the "special" positions are constrained. If some position on the chain has remainder modulo , the neighbor on the chain must have remainder

r_2 = (k - r) \bmod k,

otherwise the sum is not mod . So remainders on the chain are built from complementary pairs (r, r_2).

Let

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

If r \neq r_2, then on the path the remainders must alternate between and r_2. There are two patterns: start with (then we need positions of remainder and of r_2) or start with r_2 (then of r_2 and of ). If \text{rem}[r] = c_0 and \text{rem}[r_2] = c_1, and both exist, the ways to assign distinct elements to the constrained positions are

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

If r = r_2 (self-complementary remainder, e.g. r=0 or r=k/2 when is even), then all constrained positions must use remainder only, and if there are c_0 = \text{rem}[r] such elements, the number of ways is P(c_0,m).

We iterate over all remainders in , compute r_2 = (k-r)\bmod k and:

  • if r = r_2, we use cur = P(c_0,m);

  • if r < r_2 and r_2 exists, we use cur = P(c_0,o)P(c_1,e) + P(c_1,o)P(c_0,e);

  • if r > r_2, we skip (the unordered pair \{r,r_2\} is handled when we are at the smaller one).

For each such pair we have ways to fill the constrained positions. The remaining n-m positions are free and can be filled with the remaining elements in any order, adding a factor of (n-m)!. So we accumulate

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

Up to this point, every occurrence of the same value is treated as a different labeled object. To count distinct permutations of the multiset , we divide by for each distinct value , i.e. multiply by invfact[\text{cnt}[x]]. This is the same correction as in the m=1 case.

Complexity overall is \mathcal{O}(\sum n).

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()