2022CCPC河南省省赛(BCEHIJK)

本文精选了多项算法竞赛题目并提供了详细的解答方案,包括哈希算法、动态规划、树状数组、图论等核心算法的应用实例,适合算法爱好者及竞赛选手深入学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

B Hash

题解:
根据官方题解可以得出,子串长度不大于15为最佳长度(证明过程没看懂)。
容易看出哈希函数是以31为进制的,将模数设为P,那么一个数在模P且不大于P的情况下,越接近于P值是越大的。
盲猜子串的长度也是不会太长。
然后进行暴力DP,因为题目中的字符串是一个环,所以我们需要先枚举第一个子串的起始位置,而子串不大于15,我们只需要枚举15位即可,接下来就是进行dp转移。
f [ i ] f[i] f[i] 表示以第 i i i 个字符结尾的哈希值之和
转移方程:
d p [ i ] = max ⁡ 0 ≤ k < 15 d p [ i − k ] + f ( i − k + 1 , i ) dp[i]=\max_{0\le k< 15}dp[i-k]+ f(i-k+1,i) dp[i]=max0k<15dp[ik]+f(ik+1,i)
时间复杂度:O( 1 5 2 ∣ S ∣ 15^2|S| 152S)

template<int T>
struct ModInt {
    const static int MD = T;
    int x = 0;
    ModInt(LL x = 0) : x(x% MD) {}
    int get() { return x; }
    ModInt operator + (const ModInt& that) const { int x0 = x + that.x; return ModInt(x0 < MD ? x0 : x0 - MD); }
    ModInt operator - (const ModInt& that) const { int x0 = x - that.x; return ModInt(x0 < MD ? x0 + MD : x0); }
    ModInt operator * (const ModInt& that) const { return ModInt((long long)x * that.x % MD); }
    ModInt operator / (const ModInt& that) const { return *this * that.inverse(); }
    void operator += (const ModInt& that) { x += that.x; if (x >= MD) x -= MD; }
    void operator -= (const ModInt& that) { x -= that.x; if (x < 0) x += MD; }
    void operator *= (const ModInt& that) { x = (long long)x * that.x % MD; }
    void operator /= (const ModInt& that) { *this = *this / that; }
    ModInt inverse() const {
        int a = x, b = MD, u = 1, v = 0;
        while (b) {
            int t = a / b;
            a -= t * b; std::swap(a, b);
            u -= t * v; std::swap(u, v);
        }
        if (u < 0) u += MD;
        return u;
    }
};
typedef ModInt<mod> mint;
//取模的板子
LL f[N];
mint h[N], p[N], P = 31;
mint get_hash(int l, int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}
void solve()
{
    unordered_map<char, int> mp;
    mp['a'] = 1, mp['e'] = 2, mp['h'] = 3, mp['n'] = 4;
    string s; cin >> s;
    int n = s.size();
    s = " " + s + s;
    p[0] = 1;
    for (int i = 1; i <= n + 20; i ++ )
    {
        p[i] = p[i - 1] * P;
        h[i] = h[i - 1] * P + mp[s[i]];
    }
    LL ans = 0;
    for (int j = 1; j <= 16; j ++ )
    {
        for (int i = 0; i < n + 20; i ++ ) f[i] = 0;
        for (int i = j; i <= n + j - 1; i ++ )
        {
            for (int k = 0; k <= 15; k ++ )
            {
                int l = max(j - 1, i - k);
                ModInt t = get_hash(l + 1, i);
                f[i] = max(f[i], f[l] + t.get());
            }
        }
        ans = max(ans, f[n + j - 1]);
    }
    cout << ans << "\n";
}
int main()
{
    IOS; cin.tie(0); cout.tie(0);
    //int T; cin >> T;
    //while (T -- ) solve();
    solve();
    return 0;
}

C Serval 的试卷答案

在这里插入图片描述
在这里插入图片描述

struct node
{
    int l, r, left, right;
    int cnt, lz;
    int c[4][4], tmp[4][4];
}tr[N << 2];
LL f[N], inf[N];
LL ksm(LL a, LL b)
{
    LL res = 1;
    while (b)
    {
        if (b & 1) res = res * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return res;
}
void init()
{
    f[0] = 1;
    for (int i = 1; i <= 1e5; i ++ ) f[i] = f[i - 1] * i % mod;
    inf[100000] = ksm(f[100000], mod - 2);
    for (int i = 99999; i >= 0; i -- )
        inf[i] = inf[i + 1] * (i + 1) % mod;
}
LL C(int a, int b)
{
    return f[a] * inf[b] % mod * inf[a - b] % mod;
}
void change(node &u, int t)
{
    u.cnt = 0;
    u.left = (u.left + t) % 4, u.right = (u.right + t) % 4;
    for (int i = 0; i < 4; i ++ )
    for (int j = 0; j < 4; j ++ )
        u.tmp[i][j] = u.c[i][j];
    for (int i = 0; i < 4; i ++ )
    for (int j = 0; j < 4; j ++ )
        u.c[(i + t) % 4][(j + t) % 4] = u.tmp[i][j];
    for (int i = 0; i < 4; i ++ )
    for (int j = 0; j < 4; j ++ )
        if (i >= j) u.cnt += u.c[i][j];
}
void push_up(node &u, node &l, node &r)
{
    u.left = l.left, u.right = r.right;
    u.cnt = l.cnt + r.cnt;
    for (int i = 0; i < 4; i ++ )
    for (int j = 0; j < 4; j ++ )
        u.c[i][j] = l.c[i][j] + r.c[i][j];
    u.c[l.right][r.left] ++;
    if (l.right >= r.left) u.cnt ++;
}
void push_down(node &u, node &l, node &r)
{
    if (!u.lz) return;
    l.lz += u.lz, r.lz += u.lz;
    change(l, u.lz), change(r, u.lz);
    u.lz = 0;
}
void build(int u, int l, int r)
{
    tr[u] = {l, r};
    if (l == r)
    {
        char ch; cin >> ch;
        tr[u].left = tr[u].right = ch - 'A';
        return;
    }
    int mid = l + r >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
    push_up(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
void modify(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        change(tr[u], 1);
        tr[u].lz ++;
        return;
    }
    push_down(tr[u], tr[u << 1], tr[u << 1 | 1]);
    int mid = tr[u].l + tr[u].r >> 1;
    if (l <= mid) modify(u << 1, l, r);
    if (r > mid) modify(u << 1 | 1, l, r);
    push_up(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
int query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].cnt;
    push_down(tr[u], tr[u << 1], tr[u << 1 | 1]);
    int res = 0, flag = 0;
    int mid = tr[u].l + tr[u].r >> 1;
    if (l <= mid) res += query(u << 1, l, r), flag ++;
    if (r > mid) res += query(u << 1 | 1, l, r), flag ++;
    if (flag == 2 && tr[u << 1].right >= tr[u << 1 | 1].left) res ++;
    return res;
}
void solve()
{
    init();
    int n, m; cin >> n >> m;
    build(1, 1, n);
    while (m -- )
    {
        int op; cin >> op;
        if (op == 1)
        {
            int l, r; cin >> l >> r;
            modify(1, l, r);
            // cout << query(1, 1, n) << "\n";
        }
        else
        {
            int l, r, k; cin >> l >> r >> k;
            int c = query(1, l, r);
            // cout << c << "\n";
            if (r - l + 1 < k || k < c + 1) cout << "0\n";
            else cout << C(r - l - c, k - 1 - c) << "\n";
        }
    }
    // cout << query(1, 1, n) << "\n";
}
int main()
{
    IOS; cin.tie(0); cout.tie(0);
    //int T; cin >> T;
    //while (T -- ) solve();
    solve();
    return 0;
}

E. Serval 的俳句

在这里插入图片描述

int cnt[26];
void solve()
{
    int n; cin >> n;
    string s; cin >> s;
    char c1 = ' ', c2 = ' ', c3 = ' ';
    for (int i = 0; i < n; i ++ )
    {
        cnt[s[i] - 'a'] ++;
        if (c1 == ' ')
        {
            if (cnt[s[i] - 'a'] == 5)
            {
                c1 = s[i];
                for (int i = 0; i < 26; i ++ ) cnt[i] = 0;
            }   
            continue;
        }
        if (c2 == ' ')
        {
            if (cnt[s[i] - 'a'] == 7)
            {
                c2 = s[i];
                for (int i = 0; i < 26; i ++ ) cnt[i] = 0;
            }   
            continue;
        }
        if (c3 == ' ')
        {
            if (cnt[s[i] - 'a'] == 5)
            {
                c3 = s[i];
                for (int i = 0; i < 26; i ++ ) cnt[i] = 0;
            }   
            continue;
        }
    }
    if (c1 == ' ' || c2 == ' ' || c3 == ' ') cout << "none\n";
    else 
    {
        for (int i = 0; i < 5; i ++ ) cout << c1;
        for (int i = 0; i < 7; i ++ ) cout << c2;
        for (int i = 0; i < 5; i ++ ) cout << c3;
    }
}
int main()
{
    IOS; cin.tie(0); cout.tie(0);
    //int T; cin >> T;
    //while (T -- ) solve();
    solve();
    return 0;
}

H 旋转水管

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

char g[5][N];
int sx, sy, tx, ty, m;
bool f[5][N], flag;
bool check(int x, int y)
{
    return (x >= 2 && x <= 4 && y >= 1 && y <= m);
}
void dfs(int x, int y, int k)
{
    if (flag) return;
    if (x == tx)
    {
        if (y == ty) flag = true;
        return;
    }
    f[x][y] = true;
    if (g[x][y] == 'I')
    {
        int nx, ny;
        if (k == 0)
            nx = x + 1, ny = y;
        else if (k == 1)
            nx = x, ny = y - 1;
        else if (k == 2)
            nx = x - 1, ny = y;
        else 
            nx = x, ny = y + 1;
        if (check(nx, ny) && !f[nx][ny])
            dfs(nx, ny, k);
    }
    else
    {
        int nx, ny;
        if (k == 0 || k == 2)
        {
            nx = x, ny = y + 1;
            if (check(nx, ny) && !f[nx][ny])
                dfs(nx, ny, 3);
            ny = y - 1;
            if (check(nx, ny) && !f[nx][ny])
                dfs(nx, ny, 1);
        }
        else 
        {
            nx = x - 1, ny = y;
            if (check(nx, ny) && !f[nx][ny])
                dfs(nx, ny, 2);
            nx = x + 1;
            if (check(nx, ny) && !f[nx][ny])
                dfs(nx, ny, 0);
        }
    }
    f[x][y] = false;
}
void solve()
{
    int x, y; 
    cin >> m >> x >> y;
    for (int i = 2; i <= 4; i ++ ) 
    for (int j = 1; j <= m; j ++ )
        g[i][j] = false;
    for (int i = 2; i <= 3; i ++ )
        for (int j = 1; j <= m; j ++ )
            cin >> g[i][j];
    sx = 2, sy = x, tx = 4, ty = y;
    flag = false;
    dfs(sx, sy, 0);
    if (flag) cout << "YES\n";
    else cout << "NO\n";
}
int main()
{
    IOS; cin.tie(0); cout.tie(0);
    int T; cin >> T;
    while(T -- ) solve();
    //solve();
    return 0;
}

I Oshwiciqwq 的电梯

在这里插入图片描述

int n, m, h, k, q;
struct node
{
	int pi, ei, x, y, z;
	string st;
	bool operator < (const node &t) const
	{
		if (ei != t.ei) return ei < t.ei;
		if (st != t.st) return st > t.st;
		return pi < t.pi;
	}
};
vector<node> v[1100];
vector<array<int, 4>> e[5];
int get_pos(int x, int t, int p)
{
	int res = (x + t) % p;
	if (res == 0) res = p;
	return res;
}
int get_t(int x1, int x2, int p)
{
	if (x2 >= x1) return x2 - x1;
	return x2 + p - x1;
}
void solve()
{
	cin >> n >> m >> h >> k;
	for (int i = 1; i <= k; i ++ )
	{
		int t, x, y, z; cin >> t >> x >> y >> z;
		e[t].push_back({i, x, y, z});
	}
	cin >> q;
	int time = 0;
	for (int i = 1; i <= q; i ++ )
	{
		int t, fx, fy, fz, tx, ty, tz;
		cin >> t >> fx >> fy >> fz >> tx >> ty >> tz;
		int f = 0;
		if (fx != tx)
		{
			for (auto &[id, x, y, z] : e[0])
			{
				if (y == fy && z == fz)
				{
					int pos = get_pos(x, t, n);
					t += get_t(pos, fx, n);
					v[t].push_back({i, id, fx, fy, fz, "IN"});
					t += get_t(fx, tx, n);
					fx = tx;
					v[t].push_back({i, id, fx, fy, fz, "OUT"});
					break;
				}
			}
			f = 1;
		}
		if (fy != ty)
		{
			for (auto &[id, x, y, z] : e[1])
			{
				if (x == fx && z == fz)
				{
					if (f) t ++;
					int pos = get_pos(y, t, m);
					t += get_t(pos, fy, m);
					v[t].push_back({i, id, fx, fy, fz, "IN"});
					t += get_t(fy, ty, m);
					fy = ty;
					v[t].push_back({i, id, fx, fy, fz, "OUT"});
					break;
				}
			}
			f = 1;
		}
		if (fz != tz)
		{
			for (auto &[id, x, y, z] : e[2])
			{
				if (y == fy && x == fx)
				{
					if (f) t ++;
					int pos = get_pos(z, t, h);
					t += get_t(pos, fz, h);
					v[t].push_back({i, id, fx, fy, fz, "IN"});
					t += get_t(fz, tz, h);
					fz = tz;
					v[t].push_back({i, id, fx, fy, fz, "OUT"});
					break;
				}
			}
		}
		time = max(time, t);
	}
	for (int i = 1; i <= time; i ++ )
	{
		if (v[i].empty()) continue;
		sort(v[i].begin(), v[i].end());
		for (auto &[pi, ei, x, y, z, st] : v[i])
		{
			cout << "[" << i <<"s] Person " << pi << " " << st << " Elevator "
			     << ei << " at (" << x << ", " << y << ", " << z <<")\n";
		}
	}
}
int main()
{
	IOS; cin.tie(0); cout.tie(0);
	//int T; cin >> T;
	//while(T -- ) solve();
	solve();
	return 0;
}

J Mex Tree

在这里插入图片描述
在这里插入图片描述

int n, val[N];
int h[N], e[M], ne[M], idx;
int ans[N], sz[N], mn[N];
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void dfs(int u, int fa)
{
    sz[u] = 1, mn[u] = val[u];
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == fa) continue;
        dfs(j, u);
        sz[u] += sz[j];
        mn[u] = min(mn[u], mn[j]);
    }
}
void dfs1(int u, int fa)
{
    if (val[u] != 0 && val[u] != n)
    {
        if (mn[u] == val[u])
            ans[val[u]] = n - sz[u];
        else ans[val[u]] = 0;
    }
        
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == fa) continue;
        dfs1(j, u);
    }
}
void solve()
{
    memset(h, -1, sizeof h);
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> val[i];
    for (int i = 2; i <= n; i ++ )
    {
        int j; cin >> j;
        add(i, j), add(j, i);
    }
    ans[n] = n;
    int root;
    for (int i = 1; i <= n; i ++ )
        if (val[i] == 0)
        {
            root = i;        
            break;
        }
    dfs(root, -1);    
    for (int i = h[root]; ~i; i = ne[i])
    {
        int j = e[i];
        ans[0] = max(ans[0], sz[j]);
    }
    dfs1(root, -1);
    for (int i = 0; i <= n; i ++ ) cout << ans[i] << " ";
}
int main()
{
    IOS; cin.tie(0); cout.tie(0);
    //int T; cin >> T;
    //while (T -- ) solve();
    solve();
    return 0;
}

K 复合函数

在这里插入图片描述
在这里插入图片描述

int h[N], e[N], ne[N], idx;
bool st[N], ins[N];
int fu[N], ed[N], cir[N], cnt, t;
int sum[500][N], mp1[N], mp2[N];
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void dfs_c(int u)
{
	st[u] = ins[u] = true;
	for (int i = h[u]; ~i; i = ne[i])
	{
		int j = e[i];
		fu[j] = u; 
		if (!st[j]) dfs_c(j);
		else if (ins[j])
		{
			cnt ++;
			ed[cnt] = ed[cnt - 1];
			for (int k = u; k != j; k = fu[k])
				cir[ ++ ed[cnt]] = k;
			cir[ ++ ed[cnt]] = j;
		}
	}
	ins[u] = false;
}
void dfs(int u, int dep, int tt)
{
	sum[tt][dep] ++;
	// cout << sz << " " << dep << " " << sum[sz][dep] << "\n";
	st[u] = true;
	for (int i = h[u]; ~i; i = ne[i])
	{
		int j = e[i];
		if (st[j]) continue;
		if (!st[j]) dfs(j, dep + 1, tt);
	}
}
void solve()
{
	memset(h, -1, sizeof h);
	int n; cin >> n;
	for (int i = 1; i <= n; i ++ )
	{
		int j; cin >> j;
		add(j, i);
	}
	for (int i = 1; i <= n; i ++ )
		if (!st[i])
			dfs_c(i);
	memset(st, false, sizeof st);
	for (int i = 1; i <= ed[cnt]; i ++ ) st[cir[i]] = true;
	for (int i = 1; i <= cnt; i ++ )
	{
		int sz = ed[i] - ed[i - 1];
		if (!mp1[sz]) 
		{
			mp1[sz] = ++ t;
			mp2[t] = sz;
		}
		for (int j = ed[i - 1] + 1; j <= ed[i]; j ++ )
		{
			int k = cir[j];
			dfs(k, 0, mp1[sz]);
		}
	}
	for (int i = 1; i <= t; i ++ )
	for (int j = 1; j < N; j ++ )
		sum[i][j] += sum[i][j - 1];
	int m; cin >> m;
	while (m -- )
	{
		LL a, b, ans = 0;
		cin >> a >> b;
            if (a == b)
            {
                cout << n << "\n";
                continue;
            }
		if (a > b) swap(a, b);
		for (int i = 1; i <= t; i ++ )
		{
			int sz = mp2[i];
			// cout << sz << "\n";
			if ((b - a) % sz == 0)
			{
				if (a < N) ans += sum[i][a];
				else ans += sum[i][N - 1];
			}	
		}
		cout << ans << "\n";
	}
}
int main()
{
	IOS; cin.tie(0); cout.tie(0);
	//int T; cin >> T;
	//while(T -- ) solve();
	solve();
	return 0;
}
### 2023 CCPC河南区比题目及解析 #### 动态规划的应用——E.矩阵游戏 在2023年的CCPC河南站比中,有一道名为“矩阵游戏”的题目引起了广泛关注。该题的核心在于如何通过优化算法降低时间复杂度,从而实现高效求解。最初可以采用暴力递归的方式解决问题,但由于其指数级的时间复杂度,在大规模数据下显然不可行。因此,引入动态规划的思想成为必然选择[^1]。 以下是基于动态规划解决此问题的一个简单代码示例: ```python def dp_matrix_game(matrix, n, m): # 初始化dp数组 dp = [[0 for _ in range(m)] for __ in range(n)] # 边界条件初始化 dp[0][0] = matrix[0][0] # 填充dp表 for i in range(1, n): dp[i][0] = dp[i-1][0] + matrix[i][0] for j in range(1, m): dp[0][j] = dp[0][j-1] + matrix[0][j] for i in range(1, n): for j in range(1, m): dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + matrix[i][j] return dp[n-1][m-1] ``` 这段代码展示了如何利用二维动态规划来计算从左上角到右下角的最大路径和,其中`matrix`是一个给定的整数矩阵,而`n`和`m`分别表示矩阵的行数和列数。 #### 排列与质数问题分析——K题 另一道值得讨论的是关于排列与质数的问题(K题)。对于较小规模的情况(`n<10`),可以直接使用暴力枚举的方法找出符合条件的所有排列组合;而对于稍大一点的数据范围,则可以通过特定模式简化运算过程。具体而言,当输入参数位于区间 `[5,9]` 中时,只需依次打印从小到大的奇数序列后再接续偶数值即可满足题目需求[^2]。 例如,针对某个具体的测试样例 `n=7`, 输出应为:`1 3 5 7 2 4 6`. --- ### 参经验分享 参加此类竞不仅考验选手的技术实力,同时也对其心理素质提出了较高要求。回顾去年的比经历,团队成员之间缺乏有效沟通以及对未知领域探索不足成为了失利的主要原因所在。为了避免再次发生类似状况,建议未来参者们提前做好充分准备: - **熟悉常用算法模板**: 如图论、字符串处理等领域经典模型; - **加强合作意识培养**: 定期开展模拟训练活动增进默契程度; - **保持良好心态调整策略**: 面对难题不要轻易放弃尝试多种思路寻找突破口. ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值