2022CCPC河南省省赛(BCEHIJK)

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;
}
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值