QOJ.ac

QOJ

Time Limit: 5 s Memory Limit: 512 MB Total points: 100

# 8228. 排序

Statistics

希尔排序是一种优秀的排序算法,可以看做是一种分组插入排序,接下来我们简单介绍一下该算法:

假设现在需要对一个长度为 $n$ 的序列 $A_{0\dots n-1}$ 进行升序排序,首先我们需要确定一个整数 $m$ 和一个长度为 $m$ 递减且最后一个数为 $1$ 的序列 $d$ 作为步长序列,然后进行 $m$ 轮操作。

对于第 $i$ 轮操作,令 $t=d_i$,然后考虑把 $A$ 分成尽量均匀的 $t$ 组,具体的,我们选择把下标对 $t$ 取模相同的那些位置分到一组,然后对每个组内的数去做插入排序。

具体的,可以参照以下 C++ 代码:

void bubble_sort(vector<int> &v) {
    int n = v.size();
    for (int i = 0; i < n; i++) {
        for (int j = i; j && v[j] < v[j - 1]; j--){
            swap(v[j], v[j - 1]);
            swap_count++;
        }
    }
}

void work() {
    for (int i = 0; i < t; i++) {
        vector<int> v;
        for (int j = i; j < n; j += t) v.push_back(A[j]);
        bubble_sort(v);
        for (int j = i, k = 0; j < n; j += t, k++) A[j] = v[k];
    }
}

void shell_sort() {
    swap_count = 0;
    for (int i = 1; i <= m; i++) {
        t = d[i];
        work();
    }
}

其中的 work 函数就表示了一轮参数为 $t = d[i]$ 的操作。

现给定两个整数 $n,m$, 以及一个长度为 $m$ 的步长序列 $d$,你需要计算对于所有长度 $1 \sim n$ 的排列,在运行 shell_sort 函数后,数组元素交换次数,也就是变量 swap_count 的最大值。同时,你需要给出有多少个排列,能够达到这个最大值。

答案均需对 $10^9+7$ 取模。

输入格式

第一行两个整数 $n,m$。

第二行 $m$ 个整数,第 $i$ 个表示 $d_i$。

输出格式

一行两个整数,分别表示最多次数和达到最多次数的排列数量。答案均需对 $10^9+7$ 取模。

样例数据

样例输入

5 2
2 1

样例输出

7 2

样例解释

两个排列分别是 $[3,5,2,4,1]$ 和 $[5,2,4,1,3]$。

子任务

对于全部的数据,满足 $2\le n\le 30,1\le m\le 10, d_1\le 10, d_m=1$ 且 $\forall i=1,2,\dots,n-1$ 均有 $d_i < d_{i+1}$

  • Subtask1(18pts):$n\le 8$。
  • Subtask2(27pts):$n\le 16$。
  • Subtask3(21pts):$n\le 22$。
  • Subtask4(10pts):$m=2$。
  • Subtask5(24pts):无特殊限制。