ce_amtic's
ICPC 补题
  1. 1. EC Final 西安
  2. 2. ICPC 杭州
  3. 3. CCPC 绵阳
  4. 4. CCPC 广州 jly题
  5. 5. 鹿赛 23

我是申必是怎么回事呢?神笔相信大家都很熟悉,但是为什么我是沈璧呢?下面就让小编带大家一起了解吧。

我是神必,其实就是是伸臂了。那么我为什么会是沈比,相信大家都很好奇是怎么回事。大家可能会感到很惊讶,我怎么会是沈璧呢?但事实就是这样,小编也感到非常惊讶。

EC Final 西安

B

考虑一个子串的合法划分形如:$[…]A|ABC|AB[…]$。

考虑枚举两道竖线的位置 $i,j$,那么 $AB$ 是 $s[i:],s[j:]$ 的公共前缀。

考虑如果 $len=|AB|$ 确定,那么 $AB$ 可以唯一确定,此时的贡献是 $\sum_{k=1}^{len-1}[s[i:i+k-1]=s[i-k:i-1]]$。

显然 $len$ 是连续取值的,$2\le len\le LCP(s[i:], s[j:])$。

任意两个后缀的 LCP 可以 $O(n^2)$ DP,或者 z 函数。

定义一个 $c[i,l]=[s[i:i+l-1]=s[i-l:i-1]]$,那么 $i,j$ 的贡献实际上就是 $c$ 数组的二阶前缀和。

ICPC 杭州

A

给出 $H, n, m$,求一个 $s,d\in \mathbb R$ 使得 $H+ns+\frac {n(n+1)} 2d \text{ mod }m$ 最小。

把 $d$ 写成 $2k+t(t=0 \text{ or }1)$ 的形式,然后发现 $\frac {n(n+1)} 2 d=\frac {n(n+1)} 2t+ n(n+1)k$ ,后一项提一个 $(n+1)k$ 之后可以与 $s$ 合并。

也就是 $d$ 只取 0 或 1。两种问题本质上没有区别,那么考虑使 $H+ns\text{ mod }m$ 最小。

考虑 $ns\text{ mod }m$ 的所有取值是 $k(n,m),0\le k< m/(n,m)$。

记 $B = m-H$,显然 $ns\ge B$ 才是有效的,且我们要找到最小的 $ns$ 使得 $ns=k(n,m)\ge B$。

显然 $k=\lceil B/(n,m)\rceil$,剩下的问题是解同余方程 $ns\equiv (n,m)k\text{ (mod }m)$,exgcd 即可。

int exgcd(int a, int &x, int b, int &y){
    if(!b) return x = 1, y = 0, a;
    int g = exgcd(b, y, a % b, x);
    return y -= (a / b) * x, g;
}

CCPC 绵阳

A

博弈 DP,有待复盘:

https://codeforces.com/gym/104065/problem/A

https://atcoder.jp/contests/abc195/tasks/abc195_e

https://www.luogu.com.cn/problem/P2964

CCPC 广州 jly题

M

设长度为 $K$ 的序列 $a$,使 $0\le a_i\le m$,且 $\sum\limits_{1\le i<j\le n} a_i \text{ XOR } a_j=n$,求 $a$ 的个数。

数位 DP,首先要卡 $m$ 的限制那么从高位向低位做,设 $f[i,j,k]$ 表示考虑高 $i$ 位,现有 $j$ 个数字卡了上界,第 $0\sim i$ 位(未确定的位)两两异或的贡献之和应等于 $2^k$ 的方案数。

先看一下 $k$ 的界,首先 $k\le (K/2)^2$,因为更大的情况是无法表示的。

那么看下能不能转移,考虑 $f[i,j,k]$ 应该往哪里转移。

如果 $m$ 的 $i+1$ 位为 0,那么这种情况是简单的,因为高 $i$ 位卡上界的数字此时依然卡上界。枚举不卡上界的数字有 $j_1$ 个为 1($0\le j_1\le K -j$),转移是:

$$f[i,j,k]\binom{j-K}{j_1}\to f[i+1,j,2k-j_1(K-j_1)]$$

注意这里 $0\le 2k-j_1(K-j_1)\le(K/2)^2$。

然后如果 $m$ 的 $i+1$ 位为 1,分别枚举 $0\le j_1\le K-j$ 和 $0\le j_2\le j$ 表示没卡上界和卡上界的数字,分别选了多少个 1,转移是:

$$ f[i,j,k]\binom{K-j}{j_1}\binom{j}{j_2}\to f[i+1,j_2,2k-(j_1+j_2)(K-j_1-j_2)] $$

状态数 $O(\dfrac{K^3\log n} 4)$,转移至多 $O(K^2)$,这样是 $O(\dfrac{K^5\log n} 4)$,可过。

#include<bits/stdc++.h>
using namespace std; typedef long long LL; const int P = 1e9 + 7;
LL n, m, K, ub, C[20][20], f[2][20][400];
int getub(){
    int i = 50;
    while(i && !(n & (1ll << i)) && !(m & (1ll << i))) i--;
    return i;
}
int main(){
    freopen("_in.in", "r", stdin);
    C[0][0] = C[1][0] = C[1][1] = 1;
    for(int i = 2; i <= 18; i++){
        C[i][0] = 1;
        for(int j = 1; j <= i; j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % P;
    }
    scanf("%lld%lld%lld", &n, &m, &K), ub = getub();
    f[0][K][0] = 1; int B = (K / 2) * (K - K / 2), ans = 0; 
    for(int i = 0; i <= ub; i++){
        int u = (i & 1) ^ 1, p = i & 1, cb = ub - i; memset(f[u], 0, sizeof(f[u]));
        for(int j = 0; j <= K; j++){
            for(int k = 0; k <= B; k++){
                int sk = 2 * k + !!(n & (1ll << cb));
                if(m & (1ll << cb)){
                    // f[p][j][u] * C[k - j][j1] * C[j][j2]-> f[u][j2][su - (j1 + j2) * (k - j1 - j2)]
                    for(int j1 = 0; j1 <= K - j; j1++) for(int j2 = 0; j2 <= j; j2++){
                        int cnt = (j1 + j2) * (K - j1 - j2); if(sk < cnt || sk - cnt > B) continue;
                        f[u][j2][sk - cnt] = ((LL)C[K - j][j1] * C[j][j2] % P * f[p][j][k] + f[u][j2][sk - cnt]) % P;
                    }
                }
                else{
                    // f[p][j][u] * C[k - j][j1] -> f[u][j][su - j1 * (k - j1)]
                    for(int j1 = 0; j1 <= K - j; j1++){
                        int cnt = j1 * (K - j1); if(sk < cnt || sk - cnt > B) continue;
                        f[u][j][sk - cnt] = ((LL)C[K - j][j1] * f[p][j][k] + f[u][j][sk - cnt]) % P;
                    }
                }
            }
        }
    }
    ub = ub & 1, ub ^= 1; for(int j = 0; j <= K; j++) ans = (ans + f[ub][j][0]) % P;
    printf("%d\n", ans);
    return 0;
}

鹿赛 23

HDU 6900

没米恰,咕了