传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2227

首先,总的方案数很好求,为k^n,但合法的方案就蛋疼了,我们试着将问题转化一下,令一个方案始终合法,我们添加一个新位置将原序列首尾相连,

这样无论如何就合法了,方案数为(k + 1) ^ (n - 1),最后我们枚举在哪里断开,方案为(k - n + 1),于是ans = (k + 1) ^ (n - 1) * (k - n + 1) / k ^ n

 

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1010;
struct node {
    int a[maxn];
    node() {
        memset(a, 0, sizeof(a));
        a[0] = a[1] = 1;
    }
    void cr() {
        memset(a, 0, sizeof(a));
        a[0] = a[1] = 1;
    }
    void operator *= (int t) {
        for(int i = 1; i <= a[0]; i ++) {
            a[i] *= t;
        }
        for(int i = 1; i <= a[0]; i ++) {
            a[i + 1] += a[i] / 10;
            a[i] %= 10;
        }
        int k = a[0] + 1;
        while(a[k]) {
            a[k + 1] += a[k] / 10;
            a[k] %= 10;
            k ++;
        }
        k --;
        a[0] = k;
    }
    void operator /= (int t) {
        int res = 0;
        for(int i = a[0]; i ; i --) {
            res = res * 10 + a[i];
            a[i] = res / t;
            res %= t;
        }
        int k = a[0];
        while(k > 1 && !a[k]) k --;
        a[0] = k;
    }
    void print() {
        for(int i = a[0]; i ; i --) {
            printf("%d", a[i]);
        }
    }
}ans1, ans2;
int t, n, k;
int gcd(int a, int b) {
    if(!b) return a;
    return gcd(b, a % b);
}
int main() {
    scanf("%d", &t);
    while(t --) {
        ans1.cr(); ans2.cr();
        scanf("%d%d", &n, &k);
        if(n > k) {
            printf("0 1\n");
            continue;
        }
        int p = k - n + 1, w = 1;
        for(int i = 1; i <= n; i ++) {
            int q = gcd(p, k);
            w *= q;
            p /= q;
        }
        for(int i = 1; i < n; i ++) ans1 *= (k + 1);
        for(int i = 1; i <= n; i ++) ans2 *= k;
        ans1 *= (k - n + 1);
        ans1 /= w; ans2 /= w;
        ans1.print(); printf(" "); ans2.print(); printf("\n");
    }
    return 0;
}