“卓见杯”第五届CCPC中国大学生程序设计竞赛河南省赛-网络模拟赛 部分题解

题目链接

A Mex Query

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
bool vis[N];
 
int main()
{
#ifdef LOCAL
    //freopen("C:/input.txt", "r", stdin);
#endif
    int T;
    cin >> T;
    while (T--)
    {
        memset(vis, 0, sizeof(vis));
        int n;
        cin >> n;
        for (int i = 0; i < n; ++i)
        {
            int x;
            scanf("%d", &x);
            if (x < N)
                vis[x] = 1;
        }
        for (int i = 0; i <= n; ++i)
            if (!vis[i])
            {
                cout << i << endl;
                break;
            }
    }
 
    return 0;
}

B icebound的商店 <dp>

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1e9 + 9;
const int N = 5e3 + 10;
ll f[N]; //价钱和为i的数量
ll b[N];
 
int main()
{
#ifdef LOCAL
    //freopen("C:/input.txt", "r", stdin);
#endif
    b[1] = 1;
    b[2] = 2;
    for (int i = 3; i <= 15; ++i)
        b[i] = b[i - 1] + b[i - 2];
    int T;
    cin >> T;
    while (T--)
    {
        //memset(f, -0x3f, sizeof(f));
        memset(f, 0, sizeof(f));
        f[0] = 1;
        int n;
        cin >> n;
        for (int j = 1; j <= 15; ++j)
            for (int i = 0; i < n; ++i)
                if (i + b[j] > n)
                    break;
                else
                    f[i + b[j]] = (f[i + b[j]] + f[i]) % MOD;
        cout << f[n] << endl;
    }
 
    return 0;
}

C Nim Game <博弈>

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1e9 + 7;
const int N = 1e6 + 10;
int b[N];
int a[N], x[N];

int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	b[0] = 1;
	for (int i = 1; i < N; ++i)
		b[i] = b[i - 1] * 2 % MOD;
	int T;
	cin >> T;
	while (T--)
	{
		int n, m;
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; ++i)
			scanf("%d", &a[i]), x[i] = x[i - 1] ^ a[i];
		ll ans = 0;
		while (m--)
		{
			int l, r;
			scanf("%d%d", &l, &r);
			int res = x[r] ^ x[l - 1];
			if (res)
				ans = (ans + b[m]) % MOD;
		}
		printf("%lld\n", ans);
	}

	return 0;
}

D Defending Plan Support <树形dp>

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 5e5 + 10;
int a[N]; //点权
ll f[N], g[N]; //以i为根点权和 以i为根的代价和
ll ans = LINF;
 
struct edge
{
    int v, w, nxt;
}e[N * 2];
int h[N], idx;
void AddEdge(int u, int v, int w)
{
    e[++idx] = { v, w, h[u] };
    h[u] = idx;
}
void DFS1(int u, int fz)
{
    f[u] += a[u];
    for (int i = h[u]; i; i = e[i].nxt)
    {
        int v = e[i].v, w = e[i].w;
        if (v != fz)
        {
            DFS1(v, u);
            f[u] += f[v];
            g[u] += g[v] + f[v] * w;
        }
    }
}
void DFS2(int u, int fz, ll fzf, ll fzg) //父节点方向点权 代价
{
    ans = min(ans, g[u] + fzg);
    for (int i = h[u]; i; i = e[i].nxt)
    {
        int v = e[i].v, w = e[i].w;
        if (v != fz)
        {
            ll fv = fzf + f[u] - f[v]; //传递+所有儿子-当前儿子
            ll fw = fzg + fv * w + g[u] - g[v] - f[v] * w;
            DFS2(v, u, fv, fw);
        }
    }
}
int main()
{
#ifdef LOCAL
    freopen("C:/input.txt", "r", stdin);
#endif
    int n;
    cin >> n;
    for (int i = 1; i < n; ++i)
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        AddEdge(u, v, w);
        AddEdge(v, u, w);
    }
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    DFS1(1, 0);
    DFS2(1, 0, 0, 0);
    cout << ans << endl;
 
    return 0;
}

E Bitmap <hash>

使用滚动hash将原矩阵每行进行滚动hash,再将行hash结果每列进行滚动hash,最后的结果相当于以i,j为左上角起点大小为m的矩阵hash值。
最后尝试给B矩阵整体加上一个值,对B进行行、列hash查询出现的次数求和。
注意使用ull存储自动溢出节约时间和减少冲突,加减值时B矩阵数值范围要求在[0, 255]内。

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e3 + 10;
int a[N][N], b[N][N];
ull h[N][N];

struct HashMap //拉链法hash表
{
	static const int MXSZ = 1e7 + 20; //元素总数 查询也会创建元素 能开大就开大
	static const int MOD = 1e7 + 19; //1e3+9 1e4+7 1e6+3 1e7+19 1e8+7
	struct node
	{
		ull key;
		int val, nxt;
	}elem[MXSZ];
	int head[MOD], tot;
	void Init() //注意初始化!!!
	{
		tot = 0;
		memset(head, -1, sizeof(head));
	}
	int& operator [] (ull key)
	{
		int k = key % MOD; //取模位置
		for (int i = head[k]; ~i; i = elem[i].nxt)
			if (elem[i].key == key) //key相等
				return elem[i].val; //返回val引用
		elem[tot].key = key, elem[tot].nxt = head[k], head[k] = tot; //新建项 将原有的接在当前后并记录当前
		return elem[tot++].val = 0; //清空值并返回引用
	}
}hm;
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int n, m;
	cin >> n >> m;
	if (m > n)
		cout << 0 << endl, exit(0);
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			scanf("%d", &a[i][j]);
	int mx = 0, mi = INF;
	for (int i = 1; i <= m; ++i)
		for (int j = 1; j <= m; ++j)
			scanf("%d", &b[i][j]), mx = max(mx, b[i][j]), mi = min(mi, b[i][j]);
	ull wp = 1, wq = 1, p = 1e9 + 7, q = 1e9 + 9; //使用ull进行自动溢出
	for (int i = 0; i < m; ++i)
	{
		wp = wp * p;
		wq = wq * q;
	}
	for (int i = 1; i <= n; ++i) //按行hash
	{
		ull ha = 0;
		for (int j = 1; j <= n; ++j) //滚动hash
		{
			ha = ha * p + a[i][j];
			if (j >= m)
			{
				ha = ha - a[i][j - m] * wp;
				h[i][j] = ha;
			}
		}
	}
	hm.Init();
	for (int j = m; j <= n; ++j) //按列hash 从m开始
	{
		ull ha = 0;
		for (int i = 1; i <= n; ++i)
		{
			ha = ha * q + h[i][j];
			if (i >= m)
			{
				ha = ha - h[i - m][j] * wq;
				++hm[ha];
			}
		}
	}
	int ans = 0;
	for (int k = -mi; k <= 255 - mx; ++k) //变动
	{
		ull res = 0; //列
		for (int i = 1; i <= m; ++i)
		{
			ull ha = 0; //行
			for (int j = 1; j <= m; ++j)
				ha = ha * p + (b[i][j] + k);
			res = res * q + ha;
 		}
		ans += hm[res];
	}
	cout << ans << endl;

	return 0;
}

F 神殿 <贪心>

从第到高遍历每一个二进制位,尝试将当前位改为1看是否大于r,如果不大于则给当前位改为1。

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
 
int main()
{
#ifdef LOCAL
    //freopen("C:/input.txt", "r", stdin);
#endif
    ll l, r;
    cin >> l >> r;
    for (int i = 0; i < 32; ++i)
        if ((l | (1LL << i)) <= r) //从低向高 能改为1则改为1
            l |= (1LL << i);
        else
            break;
    cout << l << endl;
 
    return 0;
}

H 跑图 <搜索>

使用BFS搜索记录每个点的最进距离,最开始的时候把每个"1"都放入队列即可。

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 510;
int g[N][N], p[N][N];
bool vis[N][N];
int dir[4][2] = { -1, 0, 1, 0, 0, -1, 0, 1 };
int n, m;

struct node
{
	int x, y, k;
};
void BFS()
{
	memset(p, 0x3f, sizeof(p));
	queue<node> q;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
			if (g[i][j])
				q.push({ i, j, 0 }), vis[i][j] = 1;
	while (!q.empty())
	{
		int x = q.front().x, y = q.front().y, k = q.front().k; q.pop();
		p[x][y] = k;
		for (int i = 0; i < 4; ++i)
		{
			int xx = x + dir[i][0], yy = y + dir[i][1];
			if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && !vis[xx][yy])
				vis[xx][yy] = 1, q.push({ xx, yy, k + 1 });
		}
	}
}
int main()
{
#ifdef LOCAL
	//freopen("C:/input.txt", "r", stdin);
#endif
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
			scanf("%d", &g[i][j]);
	BFS();
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= m; ++j)
		{
			if (j != 1)
				putchar(' ');
			printf("%d", p[i][j]);
		}
		putchar('\n');
	}

	return 0;
}

K 520 <快速幂>

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
 
ll mpow(ll a, ll n, ll m)
{
    ll res = 1;
    while (n)
    {
        if (n & 1)
            res = res * a % m;
        a = a * a % m;
        n >>= 1;
    }
    return res;
}
int main()
{
#ifdef LOCAL
    //freopen("C:/input.txt", "r", stdin);
#endif
    ll n;
    cin >> n;
    cout << mpow(2, n, 20180520) << endl;
 
    return 0;
}

L icebound的账单

#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
 
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
 
int main()
{
#ifdef LOCAL
    //freopen("C:/input.txt", "r", stdin);
#endif
    int n;
    cin >> n;
    ll s = 0;bi
    for (int i = 0; i < n; ++i)
    {
        int x;
        scanf("%d", &x);
        s += x;
    }
    if (s > 0)
        printf("icebound is happy.\n");
    else if (s < 0)
        printf("icebound is sad.\n");
    else
        printf("icebound is ok.\n");
 
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值