分析

分析题意,我们可以发现它就是要让求 。而 是可以线性筛求出来的。所以现在问题就是如何维护矩阵中的 。因为 ,所以可以考虑二维莫队这样的时间复杂度为 。这道题卡空间,要注意线性筛时可以不用额外数组记录

后话

关于牛客挑战赛42的题就算补完了,可以说这套题还是不错的,只是有些题面稍微卡空间,题目本身不是太难,但融合和了各个方面的知识,大赞。

代码

#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
int read() {
    int x = 0,f = 0;char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-')f = 1;ch = getchar();}
    while(isdigit(ch)) {x = x * 10 + ch - '0';ch = getchar();}
    return f?-x:x;
}
const int N = 90,M = N*N*N*N,mod = 998244353;
int qpow(int x,int b) {
    int a = 1;for(;b;b>>=1,x = 1LL * x * x % mod) {
        if(b&1) a = 1LL * a * x % mod;
    }
    return a;
}
int a[N][N],n,m,limit,p[5000000],b[M],tot,pos[N];
int id[M],ans,Ans[100002],C[N*N];
struct Query{int l,r,u,d,id;}q[100002];
bool cmp(Query x,Query y) {
    if(pos[x.l] != pos[y.l]) return x.l < y.l;
    if(pos[x.r] != pos[y.r]) return x.r < y.r;
    if(pos[x.u] != pos[y.u]) return x.u < y.u;
    return x.d < y.d;
}
void add(int x) {
    if(C[x] == 0) ans = (1LL * ans + (mod - id[b[x]]) % mod + mod) % mod;
    C[x]++; 
}
void del(int x) {
    if(C[x] == 1) ans = (1LL * ans + id[b[x]] + mod) % mod;
    C[x]--;
}
void work() {
    ans = id[1] = 1;
    for(int i = 2;i <= limit;i++) {
        if(!id[i]) p[++p[0]] = i,id[i] = qpow(i,limit);
        for(int j = 1;j <= p[0] && p[j] * i <= limit;j++) {
            id[i * p[j]] = 1LL * id[p[j]] * id[i] % mod;
            if(!(i % p[j])) break;
        }
        ans = (ans + id[i]) % mod;
    }
}
int main()
{
    n = read();limit = read();
    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= n;j++) {
            a[i][j] = read();b[++tot] = a[i][j];
        }
    }
    sort(b+1,b+1+tot);tot = unique(b+1,b+1+tot) - b - 1;
    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= n;j++) {
            a[i][j] = lower_bound(b+1,b+1+tot,a[i][j]) - b;
        }
    }
    work();
    m = read();
    int block = sqrt(n-1) + 1;
    for(int i = 1;i <= n;i++) pos[i] = (i-1)/block + 1;
    for(int i = 1;i <= m;i++) {
        int x = read(),y = read(),X = read(),Y = read();
        q[i].l = min(y,Y);q[i].r = max(y,Y);
        q[i].u = min(x,X);q[i].d = max(x,X);q[i].id = i;
    }
    sort(q + 1,q + 1 + m,cmp);
    for(int l = 1,u = 1,r = 0,d = 0,i = 1;i <= m;i++) {
        while(l > q[i].l) {l--;for(int j = u;j <= d;j++) add(a[j][l]);}
        while(r < q[i].r) {r++;for(int j = u;j <= d;j++) add(a[j][r]);}
        while(u > q[i].u) {u--;for(int j = l;j <= r;j++) add(a[u][j]);}
        while(d < q[i].d) {d++;for(int j = l;j <= r;j++) add(a[d][j]);}
        while(l < q[i].l) {for(int j = u;j <= d;j++) del(a[j][l]);l++;}
        while(r > q[i].r) {for(int j = u;j <= d;j++) del(a[j][r]);r--;}
        while(u < q[i].u) {for(int j = l;j <= r;j++) del(a[u][j]);u++;}
        while(d > q[i].d) {for(int j = l;j <= r;j++) del(a[d][j]);d--;}
        Ans[q[i].id] = ans;
    }
    for(int i = 1;i <= m;i++) printf("%d\n",(Ans[i]+mod)%mod);
    return 0;
}