标签: DFS

[ZJOI2011]道馆之战 题解

[ZJOI2011]道馆之战 题解

题目地址:洛谷:【P4679】[ZJOI2011]道馆之战 – 洛谷、BZOJ:Problem 2325. — [ZJOI2011]道馆之战

题目描述

馆主为了加大难度,将道馆分成了n个房间,每个房间中是两个冰块或障碍,表示一列冰地。任意两个房间之间均有且仅有一条路径相连,即这n个房间构成一个树状结构。每个房间分成了A和B两个区域,每一区域都是一个薄冰块或者障碍物。每次只能移动到相邻房间的同一类区域(即若你现在在这个房间的A区域,那么你只能移动到相邻房间的A区域)或这个房间的另一区域。现在挑战者从房间u出发,馆主在房间v,那么挑战者只能朝接近馆主所在房间的方向过去。一开始挑战者可以在房间u的任意一个冰块区域内。如果挑战者踩过的冰块数达到了最大值(即没有一种方案踩过的冰块数更多了),那么当挑战者走到最后一个冰块上时,他会被瞬间传送到馆主面前与馆主进行道馆战。自从馆主修改规则后已经经过了m天,每天要么是有一个挑战者来进行挑战,要么就是馆主将某个房间进行了修改。对于每个来的挑战者,你需要计算出他若要和馆主进行战斗需要经过的冰块数。

输入输出格式

输入格式:
第一行包含两个正整数n和m。第2行到第n行,每行包含两个正整数x和y,表示一条连接房间x和房间y的边。房间编
号为1…n。接下来n行,每行包含两个字符。第n + k行表示房间k的两个区域,第一个字符为A区域,第二个字符为
B区域。其中“.”(ASCII码为46)表示是薄冰块,“#”(ASCII码为35)表示是障碍物。最后的m行,每行一个操作:
C u s:将房间u里的两个区域修改为s。
Q u v:询问挑战者在房间u,馆主在房间v时,挑战者能与馆主进行挑战需要踩的冰块数。如果房间u的两个区域
都是障碍物,那么输出0。
N≤ 30 000
M ≤ 80 000

输出格式:
包含若干行,每行一个整数。即对于输入中的每个询问,依次输出一个答案。

输入输出样例

输入样例#1:

5 3
1 2
2 3
2 4
1 5
.#
..
#.
.#
..
Q 5 3
C 1 ##
Q 4 5

输出样例#1:

6
3

题解

链上信息用树剖总是没错的,套个线段树。接下来的内容只研究区间信息和合并。
首先我们要求一个点出发能走的最远距离,自然要把这个答案记起来,那么用far[2][2]表示区间左1左2右1右2开始走最远距离(这里其实有点像[SHOI2008]堵塞的交通 题解 | KSkun’s Blog)。为了区间合并,我们还要记下dis[2][2]表示区间左边两个区域到右边两个区域分别的最远路径长度。
初始的时候,如果不能走,可以以-INF为初值,这样后面取max比较好办。以长度为1的区间开始设置初始值,设置的部分比较容易理解可以看代码或者类比SHOI毒瘤题。合并的时候,dis数组计算应当枚举跨越mid时是从1区域还是2区域通行的,far数组应当对跨越mid和不跨越mid分别统计。这个图示与SHOI毒瘤题其实长得差不多,可以参考那个题,结合代码理解。
查询的时候,可能要翻转其中的一半答案再合并成最后的答案。swap的时候可以考虑记下来起点在当前的哪一端。
题解参考了【BZOJ-2325】道馆之战 树链剖分 + 线段树 – DaD3zZ – 博客园,感谢原作者。

代码

// Code by KSkun, 2018/3
#include <cstdio>

#include <vector>
#include <algorithm>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1;
    char c = fgc();
    while(c < '0' || c > '9') {
        if(c == '-') neg = -1;
        c = fgc();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = fgc();
    }
    return res * neg;
}

inline bool isstatus(char c) {
    return c == '.' || c == '#';
}

inline bool readstatus() {
    char c;
    while(!isstatus(c = fgc()));
    return c == '.';
}

inline bool isop(char c) {
    return c == 'Q' || c == 'C';
}

inline char readop() {
    char c;
    while(!isop(c = fgc()));
    return c;
}

const int MAXN = 300005, INF = 1e9;

int n, m, ut, vt;
char op;
bool w[MAXN][2];
int fa[MAXN], siz[MAXN], son[MAXN], dfn[MAXN], ptn[MAXN], top[MAXN], dep[MAXN], cnt;
std::vector<int> gra[MAXN];

inline void addedge(int u, int v) {
    gra[u].push_back(v);
    gra[v].push_back(u);
}

inline void dfs1(int u) {
    for(int i = 0; i < gra[u].size(); i++) {
        int v = gra[u][i];
        if(v == fa[u]) continue;
        dep[v] = dep[u] + 1;
        fa[v] = u;
        dfs1(v);
        siz[u] += siz[v] + 1;
        if(siz[v] > siz[son[u]]) son[u] = v;
    }
}

inline void dfs2(int u, int tp) {
    top[u] = tp;
    dfn[u] = ++cnt;
    ptn[dfn[u]] = u;
    if(son[u]) dfs2(son[u], tp);
    for(int i = 0; i < gra[u].size(); i++) {
        int v = gra[u][i];
        if(v == son[u] || v == fa[u]) continue;
        dfs2(v, v);
    }
}

struct Node {
    int dis[2][2], far[2][2];
} sgt[MAXN << 2];

inline void merge(Node &rt, Node ls, Node rs) {
    rt.dis[0][0] = std::max(std::max(ls.dis[0][0] + rs.dis[0][0], ls.dis[0][1] + rs.dis[1][0]), -INF);
    rt.dis[0][1] = std::max(std::max(ls.dis[0][0] + rs.dis[0][1], ls.dis[0][1] + rs.dis[1][1]), -INF);
    rt.dis[1][0] = std::max(std::max(ls.dis[1][0] + rs.dis[0][0], ls.dis[1][1] + rs.dis[1][0]), -INF);
    rt.dis[1][1] = std::max(std::max(ls.dis[1][0] + rs.dis[0][1], ls.dis[1][1] + rs.dis[1][1]), -INF);
    rt.far[0][0] = std::max(ls.far[0][0], std::max(ls.dis[0][0] + rs.far[0][0], ls.dis[0][1] + rs.far[0][1]));
    rt.far[0][1] = std::max(ls.far[0][1], std::max(ls.dis[1][0] + rs.far[0][0], ls.dis[1][1] + rs.far[0][1]));
    rt.far[1][0] = std::max(rs.far[1][0], std::max(rs.dis[0][0] + ls.far[1][0], rs.dis[1][0] + ls.far[1][1]));
    rt.far[1][1] = std::max(rs.far[1][1], std::max(rs.dis[0][1] + ls.far[1][0], rs.dis[1][1] + ls.far[1][1]));
}

inline void reverse(Node &x) {
    std::swap(x.dis[0][1], x.dis[1][0]);
    std::swap(x.far[0][0], x.far[1][0]);
    std::swap(x.far[0][1], x.far[1][1]);
}

inline void build(int o, int l, int r) {
    if(l == r) {
        sgt[o].dis[0][0] = w[ptn[l]][0] ? 1 : -INF;
        sgt[o].far[0][0] = sgt[o].far[1][0] = w[ptn[l]][0];
        sgt[o].dis[1][1] = w[ptn[l]][1] ? 1 : -INF;
        sgt[o].far[0][1] = sgt[o].far[1][1] = w[ptn[l]][1];
        if(w[ptn[l]][0] && w[ptn[l]][1]) {
            sgt[o].far[0][0] = sgt[o].far[0][1] = sgt[o].far[1][0] = sgt[o].far[1][1] = 
                sgt[o].dis[0][1] = sgt[o].dis[1][0] = 2;
        } else {
            sgt[o].dis[0][1] = sgt[o].dis[1][0] = -INF;
        }
        return;
    }
    int mid = (l + r) >> 1, lch = o << 1, rch = (o << 1) | 1;
    build(lch, l, mid);
    build(rch, mid + 1, r);
    merge(sgt[o], sgt[lch], sgt[rch]);
}

inline void modify(int o, int l, int r, int x) {
    if(l == r) {
        sgt[o].dis[0][0] = w[ptn[l]][0] ? 1 : -INF;
        sgt[o].far[0][0] = sgt[o].far[1][0] = w[ptn[l]][0];
        sgt[o].dis[1][1] = w[ptn[l]][1] ? 1 : -INF;
        sgt[o].far[0][1] = sgt[o].far[1][1] = w[ptn[l]][1];
        if(w[ptn[l]][0] && w[ptn[l]][1]) {
            sgt[o].far[0][0] = sgt[o].far[0][1] = sgt[o].far[1][0] = sgt[o].far[1][1] = 
                sgt[o].dis[0][1] = sgt[o].dis[1][0] = 2;
        } else {
            sgt[o].dis[0][1] = sgt[o].dis[1][0] = -INF;
        }
        return;
    }
    int mid = (l + r) >> 1, lch = o << 1, rch = (o << 1) | 1;
    if(x <= mid) modify(lch, l, mid, x);
    else modify(rch, mid + 1, r, x);
    merge(sgt[o], sgt[lch], sgt[rch]);
}

inline Node query(int o, int l, int r, int ll, int rr) {
    if(l == ll && r == rr) {
        return sgt[o];
    }
    int mid = (l + r) >> 1, lch = o << 1, rch = (o << 1) | 1;
    if(rr <= mid) {
        return query(lch, l, mid, ll, rr);
    } else if(ll > mid) {
        return query(rch, mid + 1, r, ll, rr);
    } else {
        Node ls = query(lch, l, mid, ll, mid), rs = query(rch, mid + 1, r, mid + 1, rr), res;
        merge(res, ls, rs);
        return res;
    }
}

inline int query(int u, int v) {
    Node su, sv, t, t1;
    bool fu = false, fv = false, iu = true;
    int tu = top[u], tv = top[v];
    while(tu != tv) {
        if(dep[tu] > dep[tv]) {
            std::swap(tu, tv);
            std::swap(u, v);
            std::swap(su, sv);
            std::swap(fu, fv);
            iu ^= 1;
        }
        t = query(1, 1, n, dfn[tv], dfn[v]);
        if(fv) merge(t1, t, sv), sv = t1; else sv = t, fv = true;
        v = fa[tv];
        tv = top[v];
    }
    if(dep[u] > dep[v]) {
        std::swap(u, v);
        std::swap(su, sv);
        std::swap(fu, fv);
        iu ^= 1;
    }
    t = query(1, 1, n, dfn[u], dfn[v]);
    if(fv) merge(t1, t, sv), sv = t1; else sv = t, fv = true;
    if(fu) reverse(su), merge(t1, su, sv); else t1 = sv;
    return std::max(t1.far[!iu][0], t1.far[!iu][1]);
}

int main() {
    n = readint(); m = readint();
    for(int i = 1; i < n; i++) {
        ut = readint(); vt = readint();
        addedge(ut, vt);
    }
    for(int i = 1; i <= n; i++) {
        w[i][0] = readstatus();
        w[i][1] = readstatus();
    }
    dfs1(1);
    dfs2(1, 1);
    build(1, 1, n);
    while(m--) {
        op = readop();
        if(op == 'Q') {
            ut = readint(); vt = readint();
            printf("%d\n", query(ut, vt));
        }
        if(op == 'C') {
            ut = readint(); w[ut][0] = readstatus(); w[ut][1] = readstatus();
            modify(1, 1, n, dfn[ut]);
        }
    }
    return 0;
}
[POJ3683]Priest John’s Busiest Day 题解 & 2-SAT算法的优化

[POJ3683]Priest John’s Busiest Day 题解 & 2-SAT算法的优化

题目地址:POJ:3683 — Priest John’s Busiest Day

题目描述

John is the only priest in his town. September 1st is the John’s busiest day in a year because there is an old legend in the town that the couple who get married on that day will be forever blessed by the God of Love. This year N couples plan to get married on the blessed day. The i-th couple plan to hold their wedding from time Si to time Ti. According to the traditions in the town, there must be a special ceremony on which the couple stand before the priest and accept blessings. The i-th couple need Di minutes to finish this ceremony. Moreover, this ceremony must be either at the beginning or the ending of the wedding (i.e. it must be either from Si to Si + Di, or from Ti – Di to Ti). Could you tell John how to arrange his schedule so that he can present at every special ceremonies of the weddings.
Note that John can not be present at two weddings simultaneously.
每个婚礼各有两段时间可以选择,要求每对新人的婚礼的时间不能重叠,求可行方案。

输入输出格式

输入格式:
The first line contains a integer N ( 1 ≤ N ≤ 1000).
The next N lines contain the Si, Ti and Di. Si and Ti are in the format of hh:mm.

输出格式:
The first line of output contains “YES” or “NO” indicating whether John can be present at every special ceremony. If it is “YES”, output another N lines describing the staring time and finishing time of all the ceremonies.

输入输出样例

输入样例#1:

2
08:00 09:00 30
08:15 09:00 20

输出样例#1:

YES
08:00 08:30
08:40 09:00

题解

本题同样是比较裸的2-SAT题目,只是利用本题来讲解2-SAT算法的优化如何实现。下面的内容也参考了《2-SAT算法浅析》(华师一附中 赵爽)的内容。
首先是建图的部分,我们对于任意一对可能冲突的时间段分别建边即可。剩下的事情就是跑一遍2-SAT。
我们知道,2-SAT图中的有向边表示的是一种“必须选择”的关系,那么如果图中有一个强连通分量,这个SCC中只要选中了就比如选里面所有的点。那么原来看上去很大的图就可以直接缩点成一个比较小的图,我们再考虑在小图上的工作。注意,缩点后的图中,SCC间的边要反向,原因将会在之后提到。
首先,如果有对立点存在于同一个SCC中,那么无解。
接着我们考虑利用这个有向无环图的拓扑序获得答案。我们先选中一个拓扑序列中未标记的点,然后DFS处理这个点的对立点所在的SCC。既然对立点所在SCC不能被选中,那么要求必须选中它的点就也不会选中,所以在原图的边的反向上,DFS应当沿着入边一路处理到入度为0的点,这里建反边的优势就体现出来了。重复这一工作,直到所有点都有一个标记“选中”或“不选”。
接着按照所在SCC的标记来输出可行解即可。

代码

以下代码借鉴了「POJ3683」Priest John’s Busiest Day – 2-SAT – hzwer.com的写法,感谢hzwer学长。

// Code by KSkun, 2018/3
#include <cstdio>

#include <vector>
#include <stack>
#include <queue>
#include <algorithm>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1;
    char c = fgc();
    while(c < '0' || c > '9') {
        if(c == '-') neg = -1;
        c = fgc();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = fgc();
    }
    return res * neg;
}

const int MAXN = 2005;

std::vector<int> gra[MAXN], gra2[MAXN];
int n, begin[MAXN], end[MAXN], mark[MAXN], deg[MAXN];
int dfn[MAXN], low[MAXN], tot, scc, belong[MAXN], op[MAXN];
std::stack<int> sta;
std::queue<int> que;
bool insta[MAXN];

inline bool notconflict(int x, int y) {
    return begin[x] >= end[y] || begin[y] >= end[x];
}

inline void tarjan(int u) {
    dfn[u] = low[u] = ++tot;
    sta.push(u); insta[u] = true;
    for(int i = 0; i < gra[u].size(); i++) {
        int v = gra[u][i];
        if(!dfn[v]) {
            tarjan(v);
            low[u] = std::min(low[u], low[v]);
        } else if(insta[v]) {
            low[u] = std::min(low[u], dfn[v]);
        }
    }
    if(low[u] == dfn[u]) {
        int t = 0; scc++;
        while(t != u) {
            t = sta.top(); sta.pop();
            insta[t] = false;
            belong[t] = scc;
        }
    }
}

inline void dfs(int u) {
    if(mark[u]) return;
    mark[u] = -1;
    for(int i = 0; i < gra2[u].size(); i++) {
        int v = gra2[u][i];
        dfs(v);
    }
}

inline void toposort() {
    for(int i = 1; i <= scc; i++) {
        if(!deg[i]) que.push(i);
    }
    while(!que.empty()) {
        int u = que.front(); que.pop();
        if(mark[u]) continue;
        mark[u] = 1;
        dfs(op[u]);
        for(int i = 0; i < gra2[u].size(); i++) {
            int v = gra2[u][i];
            deg[v]--;
            if(!deg[v]) que.push(v);
        }
    }
}

int main() {
    n = readint();
    for(int i = 1; i <= n; i++) {
        begin[i << 1] = readint() * 60 + readint();
        end[(i << 1) - 1] = readint() * 60 + readint();
        int last = readint();
        end[i << 1] = begin[i << 1] + last;
        begin[(i << 1) - 1] = end[(i << 1) - 1] - last;
    }
    for(int i = 1; i <= n; i++) {
        for(int j = i + 1; j <= n; j++) {
            int a1 = i << 1, a2 = (i << 1) - 1, b1 = j << 1, b2 = (j << 1) - 1;
            if(!notconflict(a1, b1)) {
                gra[a1].push_back(b2);
                gra[b1].push_back(a2);
            }
            if(!notconflict(a1, b2)) {
                gra[a1].push_back(b1);
                gra[b2].push_back(a2);
            }
            if(!notconflict(a2, b1)) {
                gra[a2].push_back(b2);
                gra[b1].push_back(a1);
            }
            if(!notconflict(a2, b2)) {
                gra[a2].push_back(b1);
                gra[b2].push_back(a1);
            }
        }
    }
    for(int i = 1; i <= n << 1; i++) {
        if(!dfn[i]) tarjan(i);
    }
    for(int i = 1; i <= n; i++) {
        if(belong[i << 1] == belong[(i << 1) - 1]) {
            puts("NO");
            return 0;
        } 
        op[belong[i << 1]] = belong[(i << 1) - 1];
        op[belong[(i << 1) - 1]] = belong[i << 1];
    }
    puts("YES");
    for(int u = 1; u <= n << 1; u++) {
        for(int i = 0; i < gra[u].size(); i++) {
            int v = gra[u][i];
            if(belong[u] != belong[v]) {
                gra2[belong[v]].push_back(belong[u]);
                deg[belong[u]]++;
            }
        }
    }
    toposort();
    for(int i = 1; i <= n; i++) {
        if(mark[belong[i << 1]] == 1) {
            printf("%02d:%02d %02d:%02d\n", begin[i << 1] / 60, begin[i << 1] % 60, 
                end[i << 1] / 60, end[i << 1] % 60);
        } else {
            printf("%02d:%02d %02d:%02d\n", begin[(i << 1) - 1] / 60, begin[(i << 1) - 1] % 60, 
                end[(i << 1) - 1] / 60, end[(i << 1) - 1] % 60);
        }
    }
    return 0;
}
[HDU4903]The only survival 题解

[HDU4903]The only survival 题解

题目地址:HDUOJ:Problem – 4903

题目描述

There is an old country and the king fell in love with a devil. The devil always ask the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil. Also, this devil is looking like a very cute Loli.
Something bad actually happen. The devil makes this kingdom’s people infected by a disease called lolicon. Lolicon will take away people’s life in silence.
Although z*p is died, his friend, y*wan is not a lolicon. Y*wan is the only one in the country who is immune of lolicon, because he like the adult one so much.
As this country is going to hell, y*wan want to save this country from lolicon, so he starts his journey.
You heard about it and want to help y*wan, but y*wan questioned your IQ, and give you a question, so you should solve it to prove your IQ is high enough.
The problem is about counting. How many undirected graphs satisfied the following constraints?

  1. This graph is a complete graph of size n.
  2. Every edge has integer cost from 1 to L.
  3. The cost of the shortest path from 1 to n is k.

Can you solve it?
output the answer modulo 10^9+7
有一张n个点的无向完全图,第i个点的编号是i,每条边的边权在1到L之间的正整数,问存在多少个图使得1到n的最短路是k。

输入输出格式

输入格式:
The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains 3 integers n,k,L.
T<=5 n,k<=12,L<=10^9.

输出格式:
For each test case, output the answer in one line.

输入输出样例

输入样例#1:

2
3 3 3
4 4 4

输出样例#1:

8
668

题解

首先是方案数,我们就要找方案。考虑如果暴力地解决应该如何,我们可以首先把点1到每个点的最短路长度给枚举出来,然后构造这个图。但是仔细地分析一下,我们似乎不关心点的编号,只关心点的数量。那么这就好办了,我们只需要枚举1到该点最短路长度为定值的点有多少个就好了。
下面的叙述中,用dis代替某点最短路长度。
但是怎么统计方案数呢?考虑当前枚举到dis为x的点有i个的状况,枚举最短路长度1~x-1的方案数早已算出为res,且前面已经枚举过的点数和为tot,cnt数组表示dis为某值的点有多少个。
首先从剩下的点里面把i个点选出来,乘C_{n-tot-1}^i
这些点之间的边是无所谓的,所以每条边随便给个长度就行,乘L^{C_i^2}
dis更小的点向这些点连边,设当前枚举到了之前的dis为x'的情况,这些边要满足x' + w \geq x(j是dis更小的点,i是当前dis的点,w是这条边的边权),每条边的边权有L - (x - x') + 1种可以选择,但是如果全都选择了比x - x'大的边权,最短路长度就无法满足,因此有一部分方案不能满足,要减去,所以最后的方案数是 (L - (x - x') + 1)^{cnt_{x'}} - (L - (x - x'))^{cnt_{x'}}
把上面这一大堆乘进答案里就好啦。
到达枚举终点时tot还有可能比n小,即有点没有算过。这些点内部的边肯定是任意怎么样都行,但是要保证它们的dis比k大,这样的话,上面的“一部分方案不能满足”部分就不存在了。
注意这里计算的数据都挺大的,及时取模,小心溢出。

代码

// Code by KSkun, 2018/3
#include <cstdio>
#include <cstring>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1;
    char c = fgc();
    while(c < '0' || c > '9') {
        if(c == '-') neg = -1;
        c = fgc();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = fgc();
    }
    return res * neg;
}

const int MO = 1e9 + 7;

LL C[20][20];

inline void calc() {
    for(int i = 0; i <= 12; i++) {
        C[i][0] = 1;
        for(int j = 1; j <= i; j++) {
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MO;
        }
    }
}

inline LL fpow(LL x, LL k) {
    LL t = 1;
    while(k) {
        if(k & 1) t = (t * x) % MO;
        x = (x * x) % MO;
        k >>= 1;
    }
    return t;
}

int T, n, k, l, cnt[20];
LL ans;

inline LL cal(int x) {
    if(!cnt[x]) return 1;
    LL t1 = 1, t2 = 1;
    for(int i = 0; i < x; i++) {
        if(!cnt[i]) continue;
        if(x - i > l) return 0;
        t1 = t1 * fpow(l - (x - i) + 1, cnt[i]) % MO;
        t2 = t2 * fpow(l - (x - i), cnt[i]) % MO;
    }
    if(x == k + 1) return fpow(t1, cnt[x]);
    t1 -= t2; if(t1 < 0) t1 += MO;
    t1 = fpow(t1, cnt[x]);
    return t1;
}

inline void dfs(int x, LL res, int tot) {
    if(x == k) {
        for(int i = 1; i + tot <= n; i++) {
            LL nres = res * C[n - tot - 1][i - 1] % MO * fpow(l, C[i][2]) % MO * fpow(l, C[n - tot - i][2]) % MO;
            cnt[k] = i; cnt[k + 1] = n - tot - i;
            nres = nres * cal(k) % MO * cal(k + 1) % MO;
            ans = (ans + nres) % MO;
        }
        return;
    }
    for(int i = 0; i + tot < n; i++) {
        cnt[x] = i;
        LL nres = res * fpow(l, C[i][2]) % MO * C[n - tot - 1][i] % MO * cal(x) % MO;
        dfs(x + 1, nres, tot + i);
    }
}

int main() {
    calc();
    T = readint();
    while(T--) {
        n = readint(); k = readint(); l = readint();
        memset(cnt, 0, sizeof(cnt));
        cnt[0] = 1;
        ans = 0;
        dfs(1, 1, 1);
        printf("%lld\n", ans);
    }
    return 0;
}