Day5

发布时间 2023-07-28 18:38:11作者: Qinzh

Day 5

模拟赛

T1

\(dp_{i, j, k, 0/1}\)表示走到第 \(i, j\) 个格子,前面异或和为 \(k\) 的方案数

\(0 / 1\) 表示前面的每个路径丢了 \(/\) 没丢

转移方程:

\(f_{i,j,k,0} = f_{i-1,j,a_{i,j} \oplus k,0} + f_{i,j - 1,a_{i,j} \oplus k,0} + f_{i-1,j,k,1} + f_{i,j-1,k,1}\)

\(f_{i,j,k,1} = f_{i-1,j,a_{i,j} \oplus k,1} + f_{i,j - 1,a_{i,j} \oplus k,1}\)

\(O(mna)\)

code:

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define gt getchar
using namespace std;
inline ll read(){
    ll x=0,f=1;char ch=gt();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gt();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gt();}
    return x*f;}
const int p = 998244353;
long long n, m, a[305][305], f[305][305][257][2];
int main()
{
    n = read(), m = read();
    for(int i = 1; i <= n; ++ i)
    {
        for(int j = 1; j <= m; ++ j)
        {
            cin >> a[i][j];
        }
    }
    f[1][1][0][0] = 1;
    f[1][1][a[1][1]][1] = 1;
    for(int i = 1; i <= n; ++ i)
        for(int j = 1; j <= m; ++ j)
            for(int k = 0; k <= 127; ++ k)
            {
                if(i == j && j == 1)continue;
                f[i][j][k][0] = ((f[i - 1][j][a[i][j] ^ k][0] + f[i][j - 1][a[i][j] ^ k][0]) % p+ f[i - 1][j][k][1] + f[i][j - 1][k][1]) % p;
                f[i][j][k][1] = (f[i - 1][j][a[i][j] ^ k][1] + f[i][j - 1][a[i][j] ^ k][1]) % p;
            }
    ll ans  = 0;
    for(int i = 0; i <= 127; ++ i)ans += i * f[n][m][i][0] % p, ans = ans % p;
    cout << ans;
    return 0;
}

T2

考虑将一条合法的路径在 LCA 处计算进答案。可以设 \(f_{i,j}\) 表示 \(i\)子树内一条祖先-儿子链,且祖先 > 儿子,最后一个点是 \(j\) 的方案数,\(g_{i,j}\) 则是祖先 < 儿子,最后一个点是 \(j\) 的方案数。

\(u\) 合并一颗子树 \(v\) 的时候,答案会增加

\(ad\sum_{a < b}f_{u,a} \times g_{v, b} + f_{u,b} \times g_{v, a}\)

时间复杂度 \(O(n^2)\)

code

?

T3

见数位dp

T4

见决策单调性

区间DP

朋友

\(n\) 个房间,\(m\) 个人。第 \(i\) 个人能进入第 \([li, ri]\) 个房间。

若最终一个房间里有 \(x\) 个人,则这个房间会有 \(x\) 的快乐值。

问最大的快乐值是多少。

\(n ≤ 300\)

可以证明,最优的答案存在一个房间,使得这个房间的人最多,且能到这个房间的人全部来了。

因为对于任何一个最大值,有个人没来,那么这个人到这里来之后一定会使答案增大。

所以设 \(f_{i,j}\) 表示只考虑只能到区间 \([i, j]\) 里面的人,最大的快乐值是什么。

枚举最大值在 \(k\),那么 \(f_{i,j} = \max f_{i,k−1} + f_{k+1,j} + v\)

其中 \(v\) 表示这里面能到 \(k\) 的人。

\(v\) 不太好求,正难则反,考虑不能 到 \(k\) 的人,他们的区间一定在 \([i, k - 1]\)\([k + 1,j]\)

减去即可

复杂度 \(O(n ^ 2)\)

AGC033D

定义一个矩阵的凌乱度是:

如果这个矩阵字符全部相等,那么是 \(0\)

否则将这个矩阵切一刀,得到两个矩阵的凌乱度 \((a, b)\),对所有

\(\max(a, b) + 1\) 求最小值就是这个矩阵的凌乱度。

现在给定一个 \(n \times m\) 的矩阵,求它的凌乱度。

\(n, m ≤ 185\)

最暴力的 dp:设 \(f_{i,j,k,l}\) 表示左上角 \((i, j)\),右下角 \((k, l)\) 的矩阵

的凌乱度,那么转移直接枚举切了哪一刀就行。

时间复杂度 \(O(n^5)\) 优化可以做到 \(O(n^4)\) 很难通过。

但是可以注意到,\(f_{i,j,k,l}\) 会很小:

具体地,若区间长或宽不等于 \(1\),则可以将它对半切开

这样的答案即是 \(\log n + \log m\)

所以上面 \(f_{i,j,k,l}\) 的状态有很多其实是浪费(重复)的

因为它们的 dp 值一样。

显然 \(i, j, k\) 不变,\(f_{i, j, k, l}\) 不随 \(l\) 增大减小

所以设 \(g_{i, j, k}\) 表示最大的 \(l\) 使得 \(f_{i, j, k, l} < l\)

状态数 \(O(n^3logn)\)

考虑转移:

若横切,则贪心使上下都尽可能多,

则上面切到 \(p = g_{t -1, i, j, k}\) 下面切到 \(g_{t-1,i,p+1,k}\)

此为横切最小凌乱度

若竖切,则枚举切在 \(x\) 右边

\(g_{t,i,j,k} = \max\min(g_{t-1,i,j,x}, g_{t-1,x+1,j,k})\)

但仍无法通过

可以发现,随 \(x\) 增大,\(g_{t-1,i,j,x}\) 增大, \(g_{t-1,x + 1,j,k}\)减小

所以找最大的 \(x\) 使 \(g_{t-1,i,j,x} < g_{t-1,x + 1,j,k}\) 算在 \(x\) 还是在 \(x + 1\) 右边切更优

利用单调性找 \(x\):当 \(i, j\) 不变时,若 \(k\) 变成 \(k+1\)

则刚刚找到的 \(x,g_{t−1,i,j,x}\) 不变,\(g_{t−1,x+1,j,k}\) 可能变大。

所以当 \(k\) 变大时,\(x\) 也会跟着变大。

双指针,枚举 \(k\) 的同时,维护\(x\) 即可。

时间复杂度 \(O(n^3\log n)\)

数位DP

Luogu P9387

给定 \(n, m\),设 \(x = 1 ⊕ 2 ⊕ · · · ⊕ n − 1 ⊕ n ⊕ m\)

求有多少组 \((a, b, c)\),满足 \(a + b + c ≤ n\)\(a + b + c = m\)

\((a + b + c) ⊕ a ⊕ c = x, b > 0,\)\(10^9 + 7\) 取模。

(如果 \(a + b + c\) 既比 \(n\) 小也等于 \(m\),那么需要算两次)

\(n, m ≤ 10^{18}\),多组数据,每组数据要求复杂度 \(O(log n)\)

T3

先不管 \(a + b + c = m\),会了 \(a + b + c ≤ n\) 自然就能得到

\(a + b + c = m\) 的方案数。

可以从低到高进行 dp,设 \(f_{i,j,0/1,0/1}\) 表示从低到高 dp 完前 \(i\) 位,

向第 \(i + 1\) 位进位的个数使 \(j,b\) 是否大于 \(0\)\(a + b + c\) 的低 \(i\)

是否大于 \(n\)。转移暴力枚举 \(a, b, c\) 的低 \(i\) 位是什么就行,最后答

案是 \(f_{60,0,1,0}\)

单组时间复杂度 \(O(\log n)\)

可以类似上面的题,但由于要算和

所以分别要记 \(f_{i,j}\) 表示所有

数确定完低 \(i\) 位,且低 \(i\) 位的和等于 \(m\) 的低 \(i\) 位的方案数,

\(g_{i,j}\)表示所有合法方案中的异或和。

转移的话,\(f_{i,j}\) 直接枚举第 \(i + 1\) 位有几个 \(1\),设为 \(x\)

然后只要 \(x + j\) 的奇偶性和 \(m\)\(i + 1\) 位一样就行。

\(g_{i,j}\) 有两个部分的贡献:

一个是低于 \(i + 1\) 位的贡献,一个是第 \(i + 1\) 位的贡献。

分别算即可。即

\(g_{i, j} \times \binom{n}{x} + 2 ^ {i + 1} \times \binom{n}{x}\)

时间复杂度 \(O(n ^ 2\log m)\)

决策单调性

T4

首先,假设当我们已经选好了每个点的标准,那么每个人就一定会贪心地去他所能到达的店中标准最高的。

那么,跟刚刚的题一样,仍然可以枚举这个区间的最大值

即设 \(f_{i,j}\) 表示只考虑区间 \([i, j]\) 里的人的最大收益

然后枚举标准最高的点 \(k\),设能到达 \(k\) 的人有 \(t\) 个,

那么就是 \(f_{i,k}−1 + f_{j,k+1} + g_{k,t}\)

其中 \(g_{k,t}\) 表示有 \(t\) 个人到第 \(k\) 家店,合理选择标准能达到的最高收益

那么接下来就是求出所有 \(g_{k,t}\)

由于每个人都求这个(过程一样),

于是下面用 \(c_i\) 代表标准为 \(i\) 的花费,\(f_j\) 表示有 \(j\) 个人来的最高收益

显然 \(f_j = \max i × j − c_i\)

这个是一个标准的斜率优化式子,建出凸包来即可。

但是斜率优化是有限制的,比如这些都是能放在平面直角坐标系

上面的直线(也就是说贡献都可以写成 \(kx + b\))的形式。

有一种通用性更高,且理解起来并不比斜率优化复杂的决策单调性优化方法

对于一个 \(j\),假设 \(i_1 < i_2\),且这个时候选 \(i_2\)\(i_1\) 更加优秀,

那么对于所有 \(k > j\)\(i_2\) 都会比 \(i_1\) 优秀,那么 \(i_1\) 在这之后就没有用了。

\(i\) 从小到大的顺序加入 \(i × j − c_i\) 这条直线。

假设已经处理完了之前的所有直线,那么对于所有可能成为最优选择的

\(i_1 < i_2 < · · ·i_k\),一定有 \(i_x\)\(i_{x−1}\) 后面一些点的最优解。

我们对每个 \(i_x\) 记录 \(p_x\) 表示对于 \(j < p_x\)\(i_x\)\(i_{x+1}\) 优,

之后则是 \(i_{x+1}\) 优,那么显然 \(p_1 < p_2 < · · · p_{k−1}\)

否则若 \(p_x > p_{x+1}\),那么在 \(i_{x+1}\)\(i_x\) 优之前,\(i_{x+2}\)

就已经比 \(i_{x+1}\) 优了,所以 \(i_{x+1}\) 就不可能成为最优选择了。

那么加入 \(i\) 的时候,先算出来 \(i\)\(i_k\) 什么时候优(因为 \(i > i_k\),所以一定有个时间更优)

设为 \(y\),那么如果 \(x_k−1 > y\),那么根据上面 \(p_x\) 单调的解释,

就需要删除 \(i_k\),那么这样做就能维护出对于所有 \(j\),什么 \(i\) 最优。

做完这个之后直接枚举 $ j$,然后双指针不断从前往后扫到最后一个 \(p_x < j\)\(x\)\(i_x+1\) 就是最优的答案。

这样的时间复杂度是线性。于是,整个题时间复杂度 \(O(n^3 + nk)\)