codeforces 314 (Div 1) 题解

前言

远古神题。既然被妖姬挑出来做了,而且做的并不是那么好,那就稍微总结一下。

这场比赛的AB我全都没有想出来。
D题被卡精度然而存在整数做法。
E是赛后做的,是一道SB题,但是从这道题我知道了 1 0 5 10^5 105的数据范围也可以信仰 O ( n 2 ) O(n^2) O(n2)做法,只要大力卡常一定出奇迹。
倒是C因为套路所以做出来了。

思维极差,智商捉急。没有理由颓废了。

A Sereja and Contest

key

  • 思维

题意

n ( n ≤ 2 ∗ 1 0 5 ) n(n \le 2*10^5) n(n2105)个人,参数 k k k,每个人有一个分数 a i a_i ai,还有一个 d i = ∑ j = 1 j ≤ i − 1 ( a j ∗ ( j − 1 ) − ( n − i ) ∗ a i ) d_i=\sum_{j=1}^{j \le i-1}(a_j*(j-1)-(n-i)*a_i) di=j=1ji1(aj(j1)(ni)ai)
每次在序列中挑出 d i &lt; k d_i&lt;k di<k的序号最小的那个人踢出序列,然后后面的人序号全都前移一位。重复,直到没有人的 d i &lt; k d_i&lt;k di<k
依次输出踢出的人在原序列中的序号。

思路

高妙思路。

我们观察公式,假如去掉了一个人,那么他前面的人的 d i d_i di一定增加了,所以踢出的人序号一定是递增的。这是重要性质。

然后只要从前往后扫,记录 a j ∗ ( j − 1 ) a_j*(j-1) aj(j1)的前缀和,再记录去掉当前点前面所有该去掉的人后,当前点的序号,于是每个点的 d i d_i di都可以 O ( 1 ) O(1) O(1)算出来,与 k k k比较就好了。复杂度 O ( n ) O(n) O(n)

不得不说是道好题,我不知道为什么其他人好像一眼就切掉了。我不会的都是好题

B Sereja and Periods

key

  • DP
  • 暴力

题意

[a, b]表示b个a串连在一起。

两个字符串 [ a , b ] [a,b] [a,b] [ c , d ] [c,d] [c,d],求在前者中去掉任意个字符,能变成的 [ [ c , d ] , p ] [[c,d], p] [[c,d],p]的最大的 p p p ( l e n ( a , c ) ≤ 100 , b , d ≤ 1 0 7 ) (len(a, c) \le 100, b,d \le 10^7) (len(a,c)100,b,d107)

思路

c n t [ i ] cnt[i] cnt[i]表示从 b b b串的 i i i位置开始匹配一个 a a a串可以匹配多少个 b b b串, n x t [ i ] nxt[i] nxt[i]表示下一次要从 b b b的哪个位置开始匹配。 O ( l e n 2 ) O(len^2) O(len2)预处理。

然后 O ( n ) O(n) O(n)暴力拿 b b b a a a串匹配。

代码

这题思路还是看代码比较好懂。

#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int c, d, n, m, cnt[N], nxt[N];
char a[N], b[N];
bool exi[1000];

int Solve(int pos)
{
	int j = 0, k = pos;
	for (int i = 1; i <= n; ++ i){
		if (a[i] == b[k]) ++ k;
		if (k == m+1) k = 1, ++ j;
	}
	cnt[pos] = j;
	nxt[pos] = k;
}

int Ans()
{
	int j = 0, k = 1;
	for (int i = 1; i <= c; ++ i){
		j += cnt[k];
		k = nxt[k];
	}
	return j;
}

int main()
{
	scanf("%d%d", &c, &d);
	scanf("%s%s", a+1, b+1);
	n = strlen(a+1);
	m = strlen(b+1);

	memset(exi, 0, sizeof(exi));
	for (int i = 1; i <= n; ++ i)
		exi[a[i]] = 1;
	for (int i = 1; i <= m; ++ i)
		if (!exi[b[i]]){
			puts("0");
			return 0;
		}

	for (int i = 1; i <= m; ++ i)
		Solve(i);
	printf("%d\n", Ans()/d);
	return 0;
}

C Sereja and Subsequences

key

  • DP
  • 树状数组优化

题意

有一个长度为 n n n的序列,求所有(不同的单调非减序列的各个数相乘的积)的和。

思路

非常easy,网上博客很多比如这个

D Sereja and Straight Lines

key

  • 计算几何
  • 二分

题意

塞雷哈在平面上放了n个点。 现在Sereja想要在平面上放置两条直线,以直角相交,使得其中一条直线与x轴以45度角相交,并且从点到直线的最大距离最小。

在这个问题中,我们考虑点 ( x 1 , y 1 ) (x1,y1) x1y1 ( x 2 , y 2 ) (x2,y2) x2y2之间的距离等于 ∣ x 1 − x 2 ∣ + ∣ Y 1 − Y 2 ∣ | x1 - x2 |+| Y1 - Y2| x1x2+Y1Y2。 点与直线之间的距离是从点到属于其中一条线的某个点的最小距离。

帮助Sereja,找到从点到最佳位置直线的最大距离。

思路

看这里吧tutorial。题解厉害的地方是用 ( x + y , x − y ) (x+y, x-y) (x+y,xy)实现了旋转 45 45 45度,可以避免精度问题。

E Sereja and Squares

key

  • DP
  • 卡常

题意

给你一个长度 n ( n ≤ 1 0 5 ) n(n \le 10^5) n(n105),有一些地方已经填好括号了,求合法括号序列数。

思路

首先发现数据范围 n n n 1 0 5 10^5 105,那么 O ( n 2 ) O(n^2) O(n2)就是 1 0 10 10^{10} 1010,假如计算机1秒大概跑 1 0 9 10^9 109次运算,那么 O ( n 2 ) O(n^2) O(n2)就有过的可能。先写出DP方程, f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i位,放了 j j j个右括号的方案数。

然后你发现这个常数还挺好卡的,首先把对于每个 i i i j j j的上下界卡一卡,常数瞬间小了4倍,差不多了,但是如果精益求精的话还有很多可以卡的地方。

我目前在评测速度的第一页,可以去看看哦Amorphophallus

后记

写题解挺累的,要是什么题网上找不到题解,也不要怪谁,真的好累。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值