【训练】9.17 训练赛

A.HDU6702

签到题。

#include <bits/stdc++.h>
using namespace std;
#define int long long 

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

signed main() {
    int T = read();
    while(T --) {
        int a = read(), b = read(), ans = 0;
        if(a < b) swap(a, b);
        int base = 1;
        ans = a & b;
        if(ans) printf("%lld\n", ans);
        else printf("1\n");
    }
    return 0;
}

B.HDU6703

判断能够成为 k 的数的初始值。若该数不在1-r内则答案为k。若k在区间内则判断由该数逐个加一排列的数字的位置中第一个超过r的数是哪一个。

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000000
#define maxt 2000000
#define int long long
int n, m, ans, num[maxn], rec[maxn];
int maxx[maxt], minx[maxt], maxid[maxt];

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

struct node {
    int v, id;
    friend bool operator <(node a, node b) {
        return a.v < b.v;
    }
}a[maxn];

void Build(int p, int l, int r) {
    if(l == r) {
        maxx[p] = minx[p] = 0;
        maxid[p] = a[l].id;
        return;
    }
    int mid = (l + r) >> 1;
    Build(p << 1, l, mid), Build(p << 1 | 1, mid + 1, r);
    maxx[p] = max(maxx[p << 1], maxx[p << 1 | 1]);
    minx[p] = min(minx[p << 1], minx[p << 1 | 1]);
    maxid[p] = max(maxid[p << 1], maxid[p << 1 | 1]);
}

void Upd(int p, int l, int r, int x, int d) {
    if(l == r) {
        maxx[p] += 1, minx[p] += 1;
        return;
    }
    int mid = (l + r) >> 1;
    if(x <= mid) Upd(p << 1, l, mid, x, d);
    else Upd(p << 1 | 1, mid + 1, r, x, d);
    maxx[p] = max(maxx[p << 1], maxx[p << 1 | 1]);
    minx[p] = min(minx[p << 1], minx[p << 1 | 1]);
}

int Find(int p, int l, int r, int x) {
    if(maxid[p] <= x) return 0;
    if(l == r) return l;
    int mid = (l + r) >> 1;
    if(maxid[p << 1] > x) return Find(p << 1, l, mid, x);
    else return Find(p << 1 | 1, mid + 1, r, x);
}

int Que1(int p, int l, int r, int x, int d) {
    int mid = (l + r) >> 1;
    if(r < x) return 0;
     if(l >= x) {
        int c = Find(p, l, r, d);
        if(c) return c;
        else return 0;
    }
    int c = Que1(p << 1, l, mid, x, d);
    if(c) return c;
    else return Que1(p << 1 | 1, mid + 1, r, x, d);
}

int Find2(int p, int l, int r, int d) {
    if(maxx[p] == minx[p] && maxx[p] == d) return 0;
    if(l == r) return l;
    int mid = (l + r) >> 1;
    int c = Find2(p << 1, l, mid, d);
    if(c) return c;
    else return Find2(p << 1 | 1, mid + 1, r, d);
}

int Que2(int p, int l, int r, int x, int d) {
    int mid = (l + r) >> 1;
    if(r < x) return 0;
    if(l >= x) {
        int c = Find2(p, l, r, d);
        if(c) return c;
        else return 0;
    }
    int c = Que2(p << 1, l, mid, x, d);
    if(c) return c;
    else return Que2(p << 1 | 1, mid + 1, r, x, d);
}

signed main() {
    int T = read();
    while(T --) {
        n = read(), m = read(); ans = 0;
        for(int i = 1; i <= n; i ++) 
            a[i].v = read(), a[i].id = i, rec[a[i].v] = i;
        sort(a + 1, a + 1 + n);
        for(int i = 1; i <= n; i ++) num[a[i].id] = i;
        Build(1, 1, n);
        for(int i = 1; i <= m; i ++) {
            int opt = read();
            if(opt == 1) {
                int pos = read() ^ ans, rpos = num[pos];
                Upd(1, 1, n, rpos, 1);
            }
            else {
                int r = read() ^ ans, k = read() ^ ans;
                int v = k % 10000000; 
                if(rec[v] > r) printf("%lld\n", ans = k);
                else {
                    int fir = Que1(1, 1, n, v, r);
                    if(!fir) fir = n + 1;
                    int sec = Que2(1, 1, n, v, k / 10000000); 
                    if(!sec) sec = n + 1;
                    int anspos = min(fir, sec);
                    printf("%lld\n", ans = k + anspos - v);
                }
            }
        }
    }
    return 0;
}

C.HDU6704

后缀数组处理之后问题可以转化为求区间的第k大数,主席树即可。

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000000
#define BITS 21
#define maxt 30000000
int t[maxn], p1[maxn], p2[maxn], id[maxn], num[maxn], SA[maxn], rk[maxn];
int n, m = 27, Q, H[maxn], h[maxn], cnt, ST[maxn][BITS], bits[BITS];
int root[maxn];
char s[maxn];

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

struct node {
    int l, r, sum;
    void init() {
        l = r = sum = 0;
    }
}T[maxt];

bool cmp(int x, int y) { return x && y && (p1[x] == p1[y]) && (p2[x] == p2[y]); }
void Rsort(int *p, int *a, int *b) {
    for(int i = 1; i <= m; i ++) t[i] = 0; 
    for(int i = 1; i <= n; i ++) t[p[i]] ++;
    for(int i = 1; i <= m; i ++) t[i] += t[i - 1];
    for(int i = n; i >= 1; i --) a[t[p[b[i]]] --] = b[i];
}

void Get_SA() {
    m = 27;
    for(int i = 1; i <= n; i ++) 
        num[i] = i, p1[i] = rk[i] = s[i] - 'a' + 1, p2[i] = 0;
    for(int j = 1; ; j += j) {
        for(int i = 1; i <= n; i ++)
            p1[i] = rk[i], p2[i] = (i + j <= n) ? rk[i + j] : 0;
        Rsort(p2, id, num); Rsort(p1, SA, id);
        int p = 0;
        for(int i = 1; i <= n; i ++, m = p) 
            rk[SA[i]] = cmp(SA[i - 1], SA[i]) ? p : ++ p;
        if(m >= n) break; 
    }
}

void Get_H() {
    for(int i = 1; i <= n; i ++) {
        h[i] = max(0, h[i - 1] - 1);
        int x = i, y = SA[rk[i] - 1]; if(x < y) swap(x, y);
        while(x + h[i] <= n && s[x + h[i]] == s[y + h[i]]) h[i] ++;
    }
    for(int i = 1; i <= n; i ++) H[i] = h[SA[i]];
}

void Ins(int &p, int l, int r, int x) {
    T[++ cnt] = T[p]; p = cnt; T[p].sum ++;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(x <= mid) Ins(T[p].l, l, mid, x);
    else Ins(T[p].r, mid + 1, r, x);
}

int Que(int t1, int t2, int l, int r, int k) {
    if(l == r) {
        if(k == 1 && (T[t2].sum - T[t1].sum)) return l;
        else return -1;
    }
    int mid = (l + r) >> 1;
    int num = T[T[t2].l].sum - T[T[t1].l].sum;
    if(num >= k) return Que(T[t1].l, T[t2].l, l, mid, k);
    else return Que(T[t1].r, T[t2].r, mid + 1, r, k - num);
}

void Build_ST() {
    for(int i = 1; i <= n; i ++) ST[i][0] = H[i];
    for(int j = 1; j < BITS; j ++)
        for(int i = 1; i + bits[j] - 1 <= n; i ++)
            ST[i][j] = min(ST[i][j - 1], ST[i + bits[j - 1]][j - 1]);
}

int Get_Min(int l, int r) {
    int k = log2(r - l + 1);
    return min(ST[l][k], ST[r - bits[k] + 1][k]);
}

int Get_Pre(int id, int len) {
    int l = 1, r = id;
    while(l < r) {
        int mid = (l + r) >> 1;
        if(Get_Min(mid, id) >= len) r = mid;
        else l = mid + 1; 
    }
    return l;
}

int Get_Nxt(int id, int len) {
    int l = id, r = n;
    while(l < r) {
        int mid = (l + r) >> 1;
        if(mid + 1 <= r) mid += 1;
        if(Get_Min(id, mid) >= len) l = mid;
        else r = mid - 1;
    }
    return l;
}

int main() {
    int t = read(); bits[0] = 1;
    for(int i = 1; i < BITS; i ++) bits[i] = bits[i - 1] << 1;
    while(t --) {
        n = read(); Q = read(); cnt = 0;
        scanf("%s", s + 1);
        Get_SA();
        Get_H();
        Build_ST();
        for(int i = 1; i <= n; i ++)
            Ins(root[i] = root[i - 1], 1, n, SA[i]);
        for(int i = 1; i <= Q; i ++) {
            int l = read(), r = read(), k = read(), id = rk[l];
            int L = Get_Pre(id, r - l + 1) - 1, R = Get_Nxt(id + 1, r - l + 1);
            if(L == id - 1) if(H[id] < r - l + 1) L = id;
            if(R == id + 1) if(H[id + 1] < r - l + 1) R = id;
            printf("%d\n", Que(root[L - 1], root[R], 1, n, k));
        }
        for(int i = 1; i <= cnt; i ++) T[i].init();
        for(int i = 1; i <= n; i ++) H[i] = 0; 
    }
    return 0;
}

D.HDU6705

使用优先队列每次扩展最小的路径。问题在于如果扩展的时候把一个点上所有的边都扩展一遍则必然会超时,所以考虑扩展时对于一个点只扩展最小的一条边,等到这条路径再次到达队首再扩展稍大的一条边即可。

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000000
#define LL long long
#define pb push_back
int n, m, maxq, Q[maxn];
LL ans[maxn];

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

struct node {
    int v; LL w;
    node(int v_ = 0, LL w_ = 0) {
        v = v_, w = w_;
    }
    friend bool operator <(node a, node b) {
        return a.w < b.w;
    }
};

struct path {
    int u, v, t; LL w;
    path(int u_, int v_, LL w_, int t_) {
        u = u_, v = v_, w = w_, t = t_;
    }
    friend bool operator <(path a, path b) {
        return a.w > b.w;
    }
};
priority_queue <path> q;
vector <node> E[maxn];

void Get_K() {
    while(!q.empty()) q.pop();
    for(int i = 1; i <= n; i ++) 
        if(!E[i].empty())
            q.push(path(i, E[i][0].v, E[i][0].w, 1));
    for(int k = 1; k <= maxq; k ++) {
        path p = q.top(); q.pop();
        ans[k] = p.w;
        int u = p.u, v = p.v;
        if(!E[v].empty()) q.push(path(v, E[v][0].v, p.w + E[v][0].w, 1));
        if(p.t != 0 && p.t < E[u].size()) 
            q.push(path(u, E[u][p.t].v, p.w - E[u][p.t - 1].w + E[u][p.t].w, p.t + 1));
    }
}

int main() {
    int T = read();
    while(T --) {
        n = read(), m = read(); int q = read(); maxq = 0;
        for(int i = 1; i <= n; i ++) E[i].clear();
        for(int i = 1; i <= m; i ++) {
            int u = read(), v = read(), w = read();
            E[u].pb(node(v, w)); 
        }
        for(int i = 1; i <= n; i ++) 
            sort(E[i].begin(), E[i].end());
        for(int i = 1; i <= q; i ++) Q[i] = read(), maxq = max(maxq, Q[i]);
        Get_K();
        for(int i = 1; i <= q; i ++)
            printf("%lld\n", ans[Q[i]]);
    }
    return 0;
}

E.HDU6706

通过打表可以发现\(gcd(i^{a} - j^{a}, i ^{b} - j ^{b}) = i - j (gcd(a, b) = 1)\)。之后可以通过反演转化出两个式子,一个包含 \(i * \phi(i)\),另一个包含\(i * \mu(i)\),均可以使用杜教筛筛出。

#include <bits/stdc++.h>
using namespace std;
#define maxn 2000000
#define mod 1000000007
int cnt, pri[maxn], s[maxn], Mu[maxn], Phi[maxn], inv2, inv6, N = 1000000;
bool not_pri[maxn];
unordered_map <int, int> S;

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

int mul(int a, int b) {
    return 1ll * a * b % mod;
}

int add(int a, int b) {
    int c = a + b;
    if(c >= mod) c -= mod;
    return c;
}

int mins(int a, int b) {
    int c = a - b;
    if(c < 0) c += mod;
    return c;
}

int Qpow(int x, int t) {
    int base = 1;
    for(; t; t >>= 1, x = mul(x, x)) 
        if(t & 1) base = mul(base, x);
    return base;
}

void Pre() {
    not_pri[1] = 1, Phi[1] = 1;
    for(int i = 2; i <= N; i ++) {
        if(!not_pri[i]) pri[++ cnt] = i, Phi[i] = i - 1;
        for(int j = 1; j <= cnt; j ++) {
            int K = i * pri[j];
            if(K > N) break;
            not_pri[K] = 1;
            Phi[K] = 1ll * Phi[i] * Phi[pri[j]] % mod;
            if(!(i % pri[j])) {
                Phi[K] = 1ll * Phi[i] * pri[j] % mod;
                break;
            }
        }
    }
    for(int i = 1; i <= N; i ++) 
        s[i] = add(s[i - 1], mul(i, Phi[i]));
}

int Sum_H(int n) {
    int a = n, b = add(mul(n, 2), 1), c = add(n, 1);
    return mul(mul(a, mul(b, c)), inv6);
}

int Sum_g(int x, int y) {
    return mul(add(x, y), mul(add(mins(y, x), 1), inv2));
}

int Get_S(int n) {
    if(n <= N) return s[n];
    if(S[n]) return S[n];
    int sum = Sum_H(n);
    for(int i = 2, j; i <= n; i = j + 1) {
        j = n / (n / i);
        sum = mins(sum, mul(Sum_g(i, j), Get_S(n / i)));
    }
    return (S[n] = sum);
}

signed main() {
    Pre(); int T = read(); 
    inv2 = Qpow(2, mod - 2), inv6 = Qpow(6, mod - 2); 
    while(T --) {
        int n = read(), a = read(), b = read(); 
        printf("%d\n", mul(mins(Get_S(n), 1), inv2));
    }
    return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define maxn 2000000
#define mod 1000000007
int cnt, pri[maxn], s[maxn], Mu[maxn], Phi[maxn], inv2, inv6, N = 1000000;
bool not_pri[maxn];
unordered_map <int, int> S;

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

int mul(int a, int b) {
    return 1ll * a * b % mod;
}

int add(int a, int b) {
    int c = a + b;
    if(c >= mod) c -= mod;
    return c;
}

int mins(int a, int b) {
    int c = a - b;
    if(c < 0) c += mod;
    return c;
}

int Qpow(int x, int t) {
    int base = 1;
    for(; t; t >>= 1, x = mul(x, x)) 
        if(t & 1) base = mul(base, x);
    return base;
}

void Pre() {
    not_pri[1] = 1, Mu[1] = 1;
    for(int i = 2; i <= N; i ++) {
        if(!not_pri[i]) pri[++ cnt] = i, Mu[i] = mod - 1;
        for(int j = 1; j <= cnt; j ++) {
            int K = i * pri[j];
            if(K > N) break;
            not_pri[K] = 1, Mu[K] = mins(0, Mu[i]);
            if(!(i % pri[j])) {
                Mu[K] = 0; break;
            }
        }
    }
    for(int i = 1; i <= N; i ++) 
        s[i] = add(s[i - 1], mul(i, Mu[i]));
}

int Sum_g(int x, int y) {
    return mul(add(x, y), mul(add(mins(y, x), 1), inv2));
}

int Get_S(int n) {
    if(n <= N) return s[n];
    if(S[n]) return S[n];
    int sum = 1;
    for(int i = 2, j; i <= n; i = j + 1) {
        j = n / (n / i);
        sum = mins(sum, mul(Sum_g(i, j), Get_S(n / i)));
    }
    return (S[n] = sum);
}

int Sum_H1(int n) {
    int a = n, b = add(mul(n, 2), 1), c = add(n, 1);
    return mul(mul(a, mul(b, c)), inv6);
}

int Sum_H2(int n) {
    return mul(mul(n, add(n, 1)), inv2);
}

int Get_Sum(int n) {
    return mins(Sum_H1(n), Sum_H2(n));
}

signed main() {
    Pre(); int T = read(); 
    inv2 = Qpow(2, mod - 2), inv6 = Qpow(6, mod - 2); 
    while(T --) {
        int n = read(), a = read(), b = read(), ans = 0; 
        for(int i = 1, j; i <= n; i = j + 1) {
            j = n / (n / i);
            ans = add(ans, mul(mins(Get_S(j), Get_S(i - 1)), mul(inv2, Get_Sum(n / i))));
        }
        printf("%d\n", ans);
    }
    return 0;
}

F/G.HDU6707,6708

签到题。(G未写)。

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000000
int n, m, a[maxn], s[maxn], flag[maxn], b[maxn];

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

int main() {
    n = read(), m = read(); int cnt = 0;
    for(int i = 1; i <= n; i ++) a[i] = read();
    for(int i = 1; i <= m; i ++) s[i] = read();
    for(int i = m; i >= 1; i --)
        if(!flag[s[i]]) b[++ cnt] = s[i], flag[s[i]] = 1;
    for(int i = 1; i <= n; i ++)
        if(!flag[a[i]]) b[++ cnt] = a[i];
    for(int i = 1; i <= n; i ++) printf("%d ", b[i]);
    return 0;
}

H.HDU6709

可以发现选择煮一条鱼后会马上去钓鱼一直钓到下一条鱼钓上来之前鱼已煮好。这时有两种选择:第一种继续钓鱼,就会浪费一段时间,第二种放弃钓鱼,手头上的鱼就会少一条。贪心做法:优先选择去钓在煮的期间钓上来的鱼多的鱼,并将再钓一条浪费的时间放入到小根堆中。一直钓鱼煮鱼钓鱼直到无鱼可煮。此时可以选择小根堆中浪费时间最少的一次去再钓一条。

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000000
#define int long long
int n, k;

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); } 
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

struct fish {
    int t, num, w;
    friend bool operator <(fish a, fish b) {
        if(a.num == b.num) return a.w < b.w;
        else return a.num > b.num;
    }
}f[maxn];

struct cmp {
    bool operator () (int a, int b) {
        return a > b;
    }
};
priority_queue <int, vector <int>, cmp> q;

signed main() {
    int T = read();
    while(T --) {
        n = read(), k = read(); int ans = 0, num = 0;
        while(!q.empty()) q.pop();
        for(int i = 1; i <= n; i ++) f[i].t = read();
        for(int i = 1; i <= n; i ++)
            f[i].num = f[i].t / k, f[i].w = k - (f[i].t % k);
        sort(f + 1, f + 1 + n);
        ans += k; num += 1;
        for(int i = 1; i <= n; i ++) {
            if(num) num -= 1; 
            else if(!q.empty()) ans += q.top(), q.pop();
            else ans += k;
            num += f[i].num; ans += f[i].t;
            q.push(f[i].w);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

 I.HDU6710

虽然是期望题但不难发现本质是计数。由于每条边存在与否的概率都是0.5,所以转化为统计左侧一号点与右侧一号点之间的距离为d的图有多少个,相乘之后再除以总方案数即为期望值。考虑构建bfs分层图,则显然每个点只能与上下相邻两层的点连边(因为是二分图)。所以状态设为 dp[当前距离(层数)][左侧已加入点数][右侧已加入点数][上一层点数],然后枚举当前层点数进行转移。每次决定放入右侧一号点时累加一次答案。复杂度是 \(T *n ^{5}\),需要卡卡常数。

#include <bits/stdc++.h>
using namespace std;
#define N 32
#define Ns 35
int n, m, mod, ans, QAQ[Ns][Ns], base[Ns], C[Ns][Ns], dp[Ns * 2][Ns][Ns][Ns];

int read() {
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

int mul(int a, int b) {
    return 1ll * a * b % mod;
}

int mins(int a, int b) {
    a -= b; if(a < 0) a += mod;
    return a;
}

void Up(int &a, int b) {
    a = a + b; if(a >= mod) a -= mod;
}

int Qpow(int x, int t) {
    int ans = 1;
    for(; t; t >>= 1, x = mul(x, x)) 
        if(t & 1) ans = mul(ans, x);
    return ans;
}

void Pre() {
    for(int i = 0; i <= N; i ++) C[i][0] = 1;
    for(int i = 1; i <= N; i ++)
        for(int j = 1; j <= i; j ++)
            C[i][j] = C[i - 1][j - 1] + C[i - 1][j]; 
}

void Trans(int d, int a, int b, int lst) {
    int rem = m - b;
    for(int i = 1; i < rem; i ++) {
        int num = mul(C[rem - 1][i], QAQ[lst][i]);
        Up(dp[d + 1][a][b + i][i], mul(dp[d][a][b][lst], num));
    }
    for(int i = 0; i < rem; i ++) {
        int lft1 = n - a, lft2 = m - b - i - 1;
        int num = mul(C[rem - 1][i], mul(Qpow(2, lft1 * lft2), QAQ[lst][i + 1]));
        Up(ans, mul(d + 1, mul(dp[d][a][b][lst], mul(num, Qpow(2, lft1 * (i + 1))))));
    }
}

void Trans2(int d, int a, int b, int lst) {
    int rem = n - a;
    for(int i = 1; i <= rem; i ++) {
        int num = mul(C[rem][i], QAQ[lst][i]);
        Up(dp[d + 1][a + i][b][i], mul(dp[d][a][b][lst], num));
    }
}

void DP() {
    int tot = n + m; ans = 0;
    memset(dp, 0, sizeof(dp));
    dp[0][1][0][1] = 1;
    for(int i = 0; i < tot; i ++) 
        for(int j = 1; j <= n; j ++) 
            for(int k = 0; k <= m; k ++) {
                int lim = (i & 1) ? k : j;
                for(int t = 1; t <= lim; t ++) 
                    if(dp[i][j][k][t]) {
                        if(!(i & 1)) Trans(i, j, k, t);
                        else Trans2(i, j, k, t);
                    }
            }
}

int main() {
    int T = read();
    while(T --) {
        n = read(), m = read(), mod = read(); base[0] = 1;
        for(int i = 1; i <= N; i ++) base[i] = mul(base[i - 1], 2);
        for(int i = 0; i <= N; i ++) 
            for(int j = 0; j <= N; j ++)
            QAQ[i][j] = Qpow(mins(base[i], 1), j);
        if(n < m) swap(n, m);
        Pre();
        DP();
        int fac = Qpow(Qpow(2, n * m), mod - 2);
        ans = mul(ans, fac);
        printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2020-09-28 10:14  Twilight_Sx  阅读(155)  评论(0编辑  收藏  举报