省选联考2021vp记

卡牌游戏

考虑到将 \(a\)\(b\) 放在一起排序,最后朝上的数字必然在左端点为最小值,右端点为最大值的区间中。这个区间中至少有 \(n-m\) 个是原来的 \(a\),且对于每张卡牌必然要有 \(a\)\(b\) 在区间中。使用双指针即可实现。

矩阵游戏

vp时做 \(m=2\) 的部分分时想到:
\(b_i-b_{i-1}=a_{i+1,1}+a_{i+1,2}-a_{i-1,1}-a_{i-1,2}\)
\(b_i+b_{i-2}-b_{i-1}=a_{i+1,1}+a_{i+1,2}+a_{i-2,1}+a_{i-2,2}\)
又因为还有 \(0\le a_{i,j}\le 10^6\) 的限制条件,想到差分约束,但没有什么实际的做法。

又想到放下限制,产生了一种构造方法,将第一列和第一行设为 \(0\),剩下的就可以直接计算。但这种构造会产生大于 \(10^6\) 或小于 \(0\) 的解,但没有优化方法。

考虑正解,因为上述方法的解是未满足约束的。有一个性质:使某一行或某一列的奇数位 \(+x\),偶数位 \(-x\) 最后生成的 \(b\) 数组不变。

所以最后会产生一个矩阵(\(a_{i,j}\) 表示根据上述方法构造出的解,\(r_i\) 表示第 \(i\) 行的变化量,\(c_j\) 表示第 \(j\) 列的变化量)

\(\begin{bmatrix}a_{1,1}+r_1+c_1,a_{1,2}-r_1+c_2,a_{1,3}+r_3+c_3,\dots\\ a_{2,1}+r_2-c_1,a_{2,2}-r_2-c_2,a_{2,3}+r_2-c_3\dots\\ a_{3,1}+r_3+c_1,a_{3,2}-r_3+c_2,a_{3,3}+r_3+c_3\dots\\ \dots \end{bmatrix}\)

但这个矩阵看起来不是很可做考虑将奇数列的变化量取反,偶数行的变化量取反,得到新矩阵

\(\begin{bmatrix}a_{1,1}+r_1-c_1,a_{1,2}-r_1+c_2,a_{1,3}+r_3-c_3,\dots\\ a_{2,1}-r_2+c_1,a_{2,2}+r_2-c_2,a_{2,3}-r_2+c_3\dots\\ a_{3,1}+r_3-c_1,a_{3,2}-r_3+c_2,a_{3,3}+r_3-c_3\dots\\ \dots \end{bmatrix}\)

得到的矩阵中 \(r_i\)\(c_j\) 的关系都是满足 \(-a_{i,j}\le r_i-c_j\le 10^6-a_{i,j}(i+j\equiv 0 \pmod 2)\)\(-a_{i,j}\le c_j-r_i\le 10^6-a_{i,j}(i+j\equiv 0 \pmod 2)\),为只与减法有关的不等式,可以使用差分约束算出解。

图函数

vp时把结论推错了,非常可惜。

一个很重要的结论:若点对 \((u,v)\) 对图 \(G\) 有贡献,当且仅当 \(u<v\) 且在图 \(G\) 上存在由 \(u\)\(v\) 和由 \(v\)\(u\) 都只经过编号在 \([u+1,n]\) 的点的路径,考虑如何通过这个计算。显然去计算每个 \(f(u,v)\) 的值是非常不现实的,直接考虑点对 \((u,v)\)\(h\) 函数的贡献。一个点对的贡献是一段前缀,因此可以倒序加边求差分数组。

现在问题就到了如何求差分数组上了。令 \(f_{u,v}\) 表示由 \(u\)\(v\) 且只经过编号属于 \([u+1,n]\) 的路径中边的编号的最小值最大为多少,可以写出转移式 :

\[f_{u,v}=\max\limits_{w=u+1}^n(f_{u,v},min(f_{u,w},f_{w,v})) \]

初始若 \((u,v)\) 间有边 \(f_{u,v}=i\)\(i\) 为边 \((u,v)\) 的编号,\(f_{u,u}=m+1\)

这个式子很像 Floyd 的式子,但如果直接写 Floyd\(O(n^3)\) 的复杂度会T。优化一些无用转移,因为 \((u,v)(u<v)\) 产生贡献时只会经过编号 \(>u\) 的点,所以当 \(u>w&&v>w\) 没必要进行转移。因为CCF数据太水放过去了。

宝石

非常典的树上倍增。

先将所有颜色重新标号。若 \((s,t)\) 答案为 \(x\),从 \(s\)\(t\) 的路径上必然会按顺序出现标号为 \(1\sim x\) 的颜色。将路径拆成 \((s,lca)\)\((lca,t)\)\((s,lca)\) 上会按顺序出现编号为 \(1\sim y\) 的颜色,\((lca,t)\) 上会按顺序出现编号为 \(y+1\sim x\) 的点。\(x\) 可以通过二分得到,那么需要计算的就只有 \(y\) 的值了。令 \(f1_{u,i}\) 表示在 \((u,1)\) 上,深度最深的颜色为 \(col[u]+2^i\) 点为哪个点,\(f2_{u,i}\) 表示在 \((u,1)\) 上,深度最深的颜色为 \(col[u]-2^i\) 点为哪个点,通过倍增可以找到在 \((s,lca)\) 上可以找到的最大的 \(y\)\((lca,t)\) 上可以找到的最小的 \(y\),记为 \(y'\)。若 \(y'<=y\),则该 \(x\) 满足条件。

那么现在就只剩下一个问题了,如何求得在 \((u,1)\) 上的颜色为 \(x\) 且深度最深的点。建一棵下标为颜色的主席树,点 \(i\) 的线段树表示在 \((i,1)\) 上每个颜色的最深点的位置,每次在父亲的线段树上修改 \(col_u\) 的最深点的位置为 \(u\)

总复杂度 \(O(n^3)\)

支配

根据一些简单的结论:

  1. \(x\) 支配 \(y\)\(y\) 支配 \(z\),则 \(x\) 一定支配 \(z\),因为删除 \(x\)\(y\) 被割开,而 \(y\) 一旦不可达 \(z\) 也就随之不可达了。
  2. \(x\) 支配 \(a\)\(y\) 支配 \(a\),则 \(x,y\) 之间一定有支配关系,如不然则必定有一种情况,使得删除其中一个点后,\(1\) 可从另一个点到达 \(a\)
  3. 加入一条边后每个点的受支配集要么变小要么不变,因为图会变得更联通。
  4. 在点 \(D_x(x\not=1)\) 中必然存在一个点 \(y\),使得 \(D_x=D_y\cup {x}\),因此该点为 \(D_x\) 中支配集最大的点,令 \(fa_x=y\)
  5. \(D_x\) 大小变化,当且仅当 \(D_{fa_x}\) 大小变化或 \(fa_x\) 不在支配 \(x\)

根据前四条结论我们可以建出一颗树状结构,每个点 \(x\)\(fa_x\) 连边,这颗树叫做支配树。令 \(delp_{u,v}\) 表示删除 \(v\)\(1\) 能否到 \(u\),可以得知若 \(delp_{u,v}=0\),则 \(v\) 支配 \(u\),这样就用 \(O(n^2)\) 的时限求出所有 \(D_x\),建出支配树。

那么现在剩下的任务就只剩下判断 \(fa_x\) 是否仍然支配 \(x\) 了。令 \(f_{u,v}\) 表示删去 \(fa_v\)\(u\) 能否到达 \(v\),这个在反图上dfs一边可以求出。对于加的一条边 \((u,v)\),若删去 \(fa_x\)\(1\) 能到 \(u\) 且删去 \(fa_x\)\(v\) 能到 \(x\),则 \(D_x\) 大小会发生变化。再根据第五条结论,在支配树上bfs一遍就能求出所有受支配集变化的点。

滚榜

因为题目要求的是排名的总方案数,所以考虑贪心地分配 \(b_i\)。若 \(a_i>a_{i-1}\),令 $b_i=b_{i-1}},否则令 \(b_i=b_{i-1}+a_{i-1}-a_i\),最后如果剩下多的可以全部留个 \(b_n\)。对贡献变形可得:\(\sum b_i=\sum \max(a_i-a_{i-1},0)\times(n-i+1)\)

\(f(S,i,j)\) 表示前 \(|S|\) 位为 \(S\) 内元素,第 \(|S|\) 位为 \(i\),已选总贡献为 \(j\) 的方案数。

for(int i=1;i<=mx;i++){
        Count[i]=Count[i>>1]+(i&1);
    }
    for(int i=0;i<n;i++){
        int s=n*(a[t]-a[i]+(t<i));
        if(s<=m){
            f[1<<i][i][s]=1;
        }
    }
    for(int i=1;i<mx;i++){
        for(int j=i;j;j-=lowbit(j)){
            for(int sum=0;sum<=m;sum++){
                int p=num[lowbit(j)];
                for(int k=0;k<n;k++){
                    if(!(i&(1<<k))){
                        int s=sum+(n-Count[i])*max(0,(p<k)+a[p]-a[k]);
                        if(s<=m){
                            f[i|(1<<k)][k][s]+=f[i][p][sum];
                        }
                    }
                }
            }
        }
    }
    for(int i=0;i<=m;i++){
        for(int j=0;j<n;j++){
            ans+=f[mx][j][i];
        }
    }
posted @ 2023-03-13 14:26  luo_shen  阅读(61)  评论(0)    收藏  举报