T1
数据范围很合适..
第一档就是暴力枚举
第二档就是数位DP
第三档就是矩阵乘法
丢一下学长的博客

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
using namespace std;
LL n;
const int mod = 1e9 + 7;
struct ju 
{
    LL c[4][4];
    friend ju operator *(const ju &a, const ju &b) 
    {
        ju c;
        memset(c.c, 0, sizeof(c.c));
        for (int i = 1; i <= 3; ++i)
            for (int j = 1; j <= 3; ++j)
                for (int k = 1; k <= 3; ++k)
                    c.c[i][j] += a.c[i][k] * b.c[k][j] % mod, c.c[i][j] %= mod;
        return c;
    }
} base, ans;
LL ksm(LL a, LL b, LL mod) 
{
    LL res = 1;
    for (; b; b >>= 1, a = a * a % mod)
        if (b & 1)res = res * a % mod;
    return res;
}
ju ksm(ju a, LL b) 
{
    ju res;
    memset(res.c, 0, sizeof(res.c));
    for (int i = 1; i <= 3; ++i)res.c[i][i] = 1;
    for (; b; b >>= 1, a = a * a)
        if (b & 1)res = res * a;
    return res;
}
int main() 
{
    freopen("number.in", "r", stdin);
    freopen("number.out", "w", stdout);
    cin >> n;
    base.c[1][1] = 3; base.c[1][2] = 2; base.c[1][3] = 0;
    base.c[2][1] = 1; base.c[2][2] = 3; base.c[2][3] = 1;
    base.c[3][1] = 0; base.c[3][2] = 2; base.c[3][3] = 3;
    ans .c[1][1] = 3;
    ans .c[2][1] = 1;
    ans .c[3][1] = 0;
    ans = ksm(base, n - 1) * ans;
    (((ans.c[1][1] -= ksm(2, n, mod) + ksm(4, n, mod) % mod) %= mod) += mod) %= mod;
    ans.c[1][1] += ksm(3, n, mod);
    cout << ans.c[1][1] % mod;
    fclose(stdin); fclose(stdout);
    return 0;
}

T2
发现一个位置的值是奇数当且仅当 它所在的行加的次数+它所在的列加的次数 的和是奇数。
当有x行加了奇数次,y列加了奇数次,那么奇数个数就是(n-x)y+x(m-y)
枚举x,可以解方程得到y,特判一下(2x==n&&xm==k)的情况(化一化式子就知道了),贡献就是\(\displaystyle C_n^xC_m^yC_{\frac{r-x}{2}+n-1}^{n-1}C_{\frac{c-y}{2}+m-1}^{m-1}\)
大力卡一卡边界就行了。

#include<iostream>
#include<cstdio>
#define int long long
#define LL long long
#define DB double
using namespace std;
LL n, m, r, c, k, ans;
const int N = 400010, M = 200000, mod = 1e9 + 7;
LL jc[N], inv[N];
inline int read() 
{
    int res = 0; char ch = getchar(); bool XX = false;
    for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
    for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
    return XX ? -res : res;
}
LL ksm(LL a, LL b, LL mod) 
{
    LL res = 1;
    for (; b; b >>= 1, a = a * a % mod)
        if (b & 1)res = res * a % mod;
    return res;
}
void YYCH() 
{
    jc[0] = jc[1] = inv[0] = inv[1] = 1;
    for (int i = 2; i <= M; ++i)jc[i] = jc[i - 1] * i % mod;
    inv[M] = ksm(jc[M], mod - 2, mod);
    for (int i = M - 1; i >= 1; --i)inv[i] = inv[i + 1] * (i + 1) % mod;
}
LL C(LL n, LL m) {if (n < m)return 0; return jc[n] * inv[m] % mod * inv[n - m] % mod;}
void suan(LL x, LL y) 
{
    if (((r - x) & 1) || ((c - y) & 1))return;
    ans += C(n, x) * C(m, y) % mod * C(((r - x) >> 1) + n - 1, n - 1) % mod * C(((c - y) >> 1) + m - 1, m - 1) % mod, ans %= mod;
}
DB jue(DB x) {return x > 0 ? x : -x;}
int zheng(DB x) 
{
    return jue(x - (int)x) < 1e-3;
}
signed main() 
{
    freopen("matrix.in", "r", stdin);
    freopen("matrix.out", "w", stdout);
    cin >> n >> m >> r >> c >> k;
    YYCH();
    for (int x = (r & 1); x <= n; x += 2) 
    {
        if (n == 2 * x) 
        {
            if (x * m == k) for (int y = (c & 1); y <= m; y += 2)suan(x, y);
        } 
        else 
        {
            DB y = (DB)(k - x * m) / (n - 2 * x);
            if ((int)y < 0 || !zheng(y))continue;
            suan(x, y);
        }
    }
    cout << ans;
    fclose(stdin); fclose(stdout);
    return 0;
}

T3
前置题目线段树做法
首先离线...
原来的题目限制的只有自己这个位置,现在变成了它及它前边的k个位置。
线段树维护 区间取min,单点查询 即可。
考场上没开大空间直接凉凉...
好像这道题莫队跑得挺快的。

#include<algorithm>
#include<iostream>
#include<cstdio>
#define lson (k<<1)
#define rson ((k<<1)|1)
#define LL long long
#define DB double
using namespace std;
int n, m, q, k;
const int N = 400010, inf = 1e9;
int vis[N], a[N], ans[N], to[N][11], las[N], tr[N << 2], lz[N << 2];
struct Ask {int l, r, ans, id;} Q[N];
int my1(const Ask &a, const Ask &b) {return a.l < b.l;}
int my2(const Ask &a, const Ask &b) {return a.id < b.id;}
inline int read() 
{
    int res = 0; char ch = getchar(); bool XX = false;
    for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
    for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
    return XX ? -res : res;
}
void Write(int x, int opt) 
{
    if (opt && !x)putchar('0');
    if (!x)return; Write(x / 10, 0);
    putchar((x - x / 10 * 10) + '0');
}
void build(int k, int l, int r) 
{
    lz[k] = inf;
    if (l == r) 
    {
        tr[k] = ans[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(lson, l, mid); build(rson, mid + 1, r);
}
inline void cd(int k) 
{
    lz[lson] = min(lz[lson], lz[k]); lz[rson] = min(lz[rson], lz[k]);
    lz[k] = inf;
}
void change(int k, int l, int r, int x, int y, int v) 
{
    if (x <= l && r <= y) 
    {
        lz[k] = min(lz[k], v);
        return;
    }
    if (lz[k] != inf)cd(k);
    int mid = (l + r) >> 1;
    if (x <= mid)change(lson, l, mid, x, y, v);
    if (mid + 1 <= y)change(rson, mid + 1, r, x, y, v);
}
int ask(int k, int l, int r, int pos) 
{
    if (l == r) 
    {
        return min(lz[k], tr[k]);
    }
    if (lz[k] != inf)cd(k);
    int mid = (l + r) >> 1;
    if (pos <= mid)return ask(lson, l, mid, pos);
    else return ask(rson, mid + 1, r, pos);
}
inline void solve2() 
{
    for (int i = 1; i <= q; ++i) 
    {
        Q[i].l = read(); Q[i].r = read(); Q[i].id = i;
    }
    sort(Q + 1, Q + 1 + q, my1);
    int now = 1;
    for (int i = 1; i <= m; ++i) 
    {
        for (int j = max(1, a[i] - k + 1); j <= a[i]; ++j) 
        {
            vis[j] = 1;
            to[las[j]][a[las[j]] - j] = i;
            las[j] = i;
        }
        while (vis[now])++now;
        ans[i] = now;
    }
    for (int i = 1; i <= n; ++i)to[las[i]][a[las[i]] - i] = m + 1;
    build(1, 1, m);
    now = 1; int pos;
    for (int i = 1; i <= m; ++i) 
    {
        while (Q[now].l == i) 
        {
            Q[now].ans = ask(1, 1, m, Q[now].r);
            ++now;
        }
        for (int j = max(1, a[i] - k + 1); j <= a[i]; ++j) 
        {
            pos = to[i][a[i] - j] - 1;
            change(1, 1, m, i, pos, j);
        }
    }
    sort(Q + 1, Q + 1 + q, my2);
    for (int i = 1; i <= q; ++i) 
    {
        if (Q[i].ans > n - k + 1)puts("-1");
        else Write(Q[i].ans, 1), putchar('\n');
    }
}
int main() 
{
    freopen("stall.in", "r", stdin);
    freopen("stall.out", "w", stdout);
    cin >> n >> m >> q >> k;
    for (int i = 1; i <= m; ++i)a[i] = read();
    solve2();
    fclose(stdin); fclose(stdout);
    return 0;
}

任何时候,都不要自信到连暴力分都不要。