CSP-S 2019 第二轮 DAY2 简单解析(含部分分代码)

CSP-S 2019第二轮第二试昨天上午正式结束了,赛后仔细拜读了DAY2的三个题目,难!但也是明年NOI选手不错的试炼机会,高分选手大概率也是明年NOI赛场上的选手。

 

第一题:Emiya 家今天的饭,比较难的动态规划

第二题:划分,动态规划,高精度,单调队列

第三题:树的重心,dfs序,线段树

 

以下代码均在oitiku测试,第一题Emiya 家今天的饭,O(n^2m)的算法仅得到84分,超时了4个点,理论上应该是可以通过的:)第二题划分,由于数据太大,写了高精度,写的不是太好,最后三个点在oitiku上MLE了,仅得到88分,之后再来改进:)第三题仅写了一下大致想法,往后再来补坑

 

 

CSP-S 2019 D2T1 Emiya 家今天的饭

思路:容斥,方案计数,对998, 244, 353取余数,已经在预示着这题是动态规划了。先考虑无限制情况下,显然是一个普及组难度的dp问题,然后考虑k/2的限制,我们可以从总的方案中减去不符合k/2限制的方案数即可。

代码如下:

 

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 210;
const int maxm = 2100;
const long long mod = 998244353;

long long g[maxn][maxn], f[maxn][maxn], a[maxn][maxm], line[maxn];
int n, m;

int main() {
	freopen("meal.in", "r", stdin);
	freopen("meal.out", "w", stdout);

	cin >> n >> m;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j) {
			cin >> a[i][j];
			a[i][j] %= mod;
			line[i] = (line[i] + a[i][j]) % mod;
		}

	long long sum = 0;
	g[0][0] = 1; 
	for (int i = 1; i <= n; ++i)
		for (int j = 0; j <= i; ++j) {
			g[i][j] = g[i - 1][j];
			for (int k = 1; k <= m; ++k) {
				if (j > 0)
					g[i][j] += g[i - 1][j - 1] * a[i][k] % mod;
				g[i][j] %= mod;
			}
		}

	for (int i = 1; i <= n; ++i)
		sum = (sum + g[n][i]) % mod;

	for (int l = 1; l <= m; ++l) {
		memset(f, 0, sizeof(f));

		// 差值可能为负数,偏移量为n + 1
		f[0][n + 1] = 1;
		for (int i = 1; i <= n; ++i)
			for (int j = n + 1 - i; j <= i + n + 1; ++j) {
				f[i][j] = f[i - 1][j];
				f[i][j] += (f[i - 1][j - 1] * a[i][l]) % mod;
				f[i][j] += (f[i - 1][j + 1] * ((line[i] - a[i][l] + mod) % mod)) % mod;
				f[i][j] %= mod;
			}

		for (int i = 1; i <= n; ++i) {
			sum = (sum - f[n][i + n + 1]) % mod;
			if (sum < 0)
				sum += mod;
		}

	}
	cout << sum << endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}





 

 

CSP-S 2019 D2T2 划分

思路:根据数据规模显然是要一个O(n)的算法,粗略的就是先贪心,然后典型的序列型动态规划。dp一下n^2,必须使用单调队列优化至O(n)。最后由于数据太大,需要用高精度或者别的取巧的方法优化一下,我们这里使用传统的高精度来写一下:)

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 4e7, maxm = 1e5;

int n, type, x, y, z, m;
int a[maxn], p[maxm], l[maxm], r[maxm], b[maxn + 1], q[maxn + 1], head, tail;
long long sum[maxn + 1];

struct BigInteger {
    
    int len, data[50];
    
    BigInteger(string& s) {
        memset(data, 0, sizeof(data));
        len = s.size();
        for (int i = 0; i < len; ++i)
            data[i] = s[len - i - 1] - '0';
    }
    
    void set(long long num) {
        len = 0;
        memset(data, 0, sizeof(data));
        while (num > 0) {
            data[len] = num % 10;
            len ++;
            num /= 10;
        }
        len ++;
    }

    BigInteger() {
        len = 0;
        memset(data, 0, sizeof(data));
    }
    
    BigInteger operator + (const BigInteger &b) {
        BigInteger c;

        c.len = 0;
        while(c.len <= max(len, b.len) + 1) {
            c.data[c.len] += data[c.len] + b.data[c.len];
            c.data[c.len + 1] += c.data[c.len] / 10;
            c.data[c.len] %= 10;
            c.len ++;
        }
        while (c.len > 0 && c.data[c.len] == 0)
            c.len --;

        c.len++;
        
        return c;
    }
    
    BigInteger operator * (const BigInteger &b) {
        BigInteger c;

        c.len = len + b.len - 1;
        for (int i = 0; i < len; ++i)
            for (int j = 0; j < b.len; ++j)
                c.data[i + j] += data[i] * b.data[j];
        
        for (int i = 1; i < c.len; ++i) {
            c.data[i] += c.data[i - 1] / 10;
            c.data[i - 1] %= 10;
        }
        
        while (c.data[c.len - 1] >= 10) {
            c.data[c.len] = c.data[c.len - 1] / 10;
            c.data[c.len - 1] %= 10;
            c.len += 1;
        }

        return c;
    }

    string toString() {
        string s = "";
        for (int i = len - 1; i >= 0; --i)
            s += (char)(data[i] + '0');
        return s;
    }
};

int main() {
    freopen("partition.in", "r", stdin);
    freopen("partition.out", "w", stdout);

    cin >> n >> type;
    if (type == 0) {
        for (int i = 0; i < n; ++i)
            cin >> a[i];
    } else {
        cin >> x >> y >> z >> a[0] >> a[1] >> m;
        for (int i = 2; i < n; ++i)
            a[i] = (1LL * x * a[i - 1] + 1LL * y * a[i - 2] + z) & 0x3fffffff;
        for (int i = 0; i < m; ++i)
            cin >> p[i] >> l[i] >> r[i];
        for (int i = 0, j = 0; i < n; ++i) {
            if (i == p[j]) ++j;
            a[i] = a[i] % (r[j] - l[j] + 1) + l[j];
        }
    }

    for (int i = 0; i < n; ++i)
        sum[i + 1] = sum[i] + a[i];

    q[tail++] = 0;
    for (int i = 0; i < n; ++i) {
        while (head + 1 < tail && 2 * sum[q[head + 1]] - sum[b[q[head + 1]]] <= sum[i + 1])
            ++head;
        b[i + 1] = q[head];
        while (head < tail && 2 * sum[i + 1] - sum[b[i + 1]] <= 2 * sum[q[tail - 1]] - sum[b[q[tail - 1]]])
            --tail;
        q[tail++] = i + 1;
    }

    BigInteger ans, tmp;
    for (int i = n; i > 0; i = b[i]) {
        tmp.set((long long)(sum[i] - sum[b[i]]));
        tmp = tmp * tmp;
        ans = ans + tmp;
    }
    cout << ans.toString() << endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}



 

CSP-S D2T3 树的重心

思考:

https://codeforces.com/problemset/problem/686/D,恰好比赛前跟同学们也讨论过子树重心的问题。

 

树的问题的确可以深挖很多有趣的性质,这也是我比较喜欢树上的问题的一些原因。这可能也是为什么树的题目出那么多的原因之一吧。逆向思维一下,如果这点是树的重心,那么一定是删除size最大的子树里面的边。本质dfs序,然后用线段树维护即可。

 

 

2019赛季告一段落,高潮已过,停课冲刺的同学们该调整心情回归课堂了,冲刺明年NOI的同学,革命尚未成功,同志仍需努力!

 

每一位同学都值得为这次CSP-J/S赛写一个总结,心得,感悟,亦或者是回顾自己的学习C++/算法竞赛、OI的历程。

 

灿烂的明天正在等着你们!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
csp-s是中国信息学奥林匹克竞赛的高中别赛事,而第二轮则是指整个比赛为两轮进行。2023年的csp-s第二轮将继续推动学生们的计算机科学学习和技能发展。 第二轮比赛通常更加复杂和挑战性,要求参赛者具备扎实的计算机基础知识和技能。比赛题目涵盖了算法、数据结构、编程语言等多个方面,旨在考验学生的思维逻辑和解决问题的能力。 对于参赛者而言,csp-s第二轮2023是一个展示自己技能的机会,也是一个不断学习和成长的过程。比赛的形式为在线答题,参赛者需要在规定的时间内完成一系列的编程题目。在这个过程中,他们将面对一定的时间压力和竞争压力,需要在有限的时间内迅速思考、捕捉问题的本质,并找到最佳的解决方法。 除了对个人技能的考察外,csp-s第二轮还鼓励参赛者之间的合作和交流。在解题过程中,可以借鉴他人的思路和解法,从而共同进步。这也是csp-s比赛独特的地方之一,它不仅是个人能力的竞技场,更是一个团队合作的平台。 对于学校和教育机构而言,csp-s第二轮2023是一个促进计算机科学教育的机会。通过参与这样的比赛,学生们可以接触到实际的编程题目,提高他们的实践能力和解决问题的能力。同时,教师们也可以通过这个平台了解学生的学习情况和技能水平,为他们提供更加有针对性的教学。 总而言之,csp-s第二轮2023将是一场精彩的比赛,为学生们提供展示自己技能和学习成果的机会。在参与比赛的过程中,他们将不断锻炼和提高自己的计算机科学技能,并与其他优秀的学生进行交流和合作。这将有助于他们未来的学习和职业发展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值