签到题
A
4min 1Y
C
45min 3Y
题意
给两个串,要把第一个串变成第二个串。每次选择一个半径r
,然后以第一个串的中心为中心,r
为半径,左右翻转。问最少几次操作?
题解
细节有点多。
- 先是输出
-1
的情况。这个很好考虑 - 然后遍历s1串,对于位置
i
,如果需要翻转(s1[i]=s2[n+1-i]
),则打上标记1,不需要翻转(s1[i]=s2[i]
).则打上标记0,如果翻不翻转都可以(s1[i]=s1[n+1-i]
),打上标记2。 - 遍历
[1,n/2]
,对于打上标记2的位置,我们要决定是翻还是不翻,根据贪心,我们可以怠惰一点!对于打上标记2的位置,和前一个位置保持一致即可。
F
25min 1Y
题解
统计一下每个数字出现了多少次,出现了x
次,对答案的贡献则为x!
,相乘即为答案。
J
42min 2Y
题解
按题意模拟。
冷静分析一下开局
- 开场看了C觉得很基本,然后过了A,开始写C。
- C细节没考虑清楚,用了
10min
,WA on test 2!
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 100000 + 10;
int T;
char s1[N], s2[N], s3[N];
bool ok[N];
int main() {
scanf("%d", &T);
while (T --) {
scanf("%s %s", s1+1, s2+1);
int n = strlen(s1+1);
int mid = (n+1)/2;
if (s1[mid] != s2[mid]) {
printf("-1
"); continue;
}
bool gg = 0;
for (int i=1;i<mid;i++) {
if (s1[i]==s2[i] && s1[n-i+1]==s2[n-i+1])
ok[i] = 1;
else if (s1[i]==s2[n-i+1] && s1[n-i+1]==s2[i])
ok[i] = 0;
else
gg = 1;
}
if (gg) {
printf("-1
"); continue;
}
int ans = 0;
ok[0] = 1;
for(int i=1;i<mid;i++) {
if (ok[i] != ok[i-1])
ans ++;
}
printf("%d
", ans);
}
}
完全没有考虑s1[i]=s1[n+1-i]
的情况。
用了6分钟fix了一下。s1[i]=s1[n+1-i]
int ans = 0;
ok[0] = 1;
for(int i=1;i<mid;i++) {
if (ok[i] != ok[i-1] && ok[i] != 2)
ans ++;
}
printf("%d
", ans);
然后喵了个呜,又一次WA2
- 我逃跑,用了5min时间过了F
- 用了10min的时间J题
WA2
- 用了5min的时间fix了一下,人调换方向那个地方写得意识有点模糊。
- 用了2min时间fix了一下C,很沙比的错误,比如说
n = 7
,前3位,标记为0 2 0
的情况就智障掉了。
前期比较容易细节没考虑清楚就上去写代码。C
,J
这两个模拟题都是这个原因吧。开始写代码之间,大概是抱着“随便搞搞就好”的想法。这种态度很沙比的啊。
- 我在求什么?
- 在模拟的过程,变量会如何变化?
这两个问题都考虑得不清楚吧!
中档题
B
Hash的做法很容易看出。然后就unlimited WA TLE MLE
搞Hash的经验严重不足?
边的种数不会超过n种,因此我们放n个桶。每个桶记录这种边出现的次数。
然后就是对一个XXX进制下,n位数的hash了【双hash保平安】
#include <iostream>
#include <algorithm>
#include <vector>
#include <unordered_map>
using namespace std;
typedef long long LL;
const int N = 10000008;
const LL MOD1 = 100000007;
const LL MOD2 = 923439347;
int T;
int n, x, y;
int val[N]; vector<int> v;
LL k1[N], k2[N];
unordered_map< LL, int > mp;
int main() {
scanf("%d", &T);
k1[0] = k2[0] = 1;
for(int i=1;i<N;i++) {
k1[i]=k1[i-1]*10007LL%MOD1;
k2[i]=k2[i-1]*20007LL%MOD2;
}
while (T --) {
scanf("%d", &n);
v.clear();
for (int i = 1; i <= n; i ++) {
scanf("%d %d", &x, &y);
if (x > y) swap(x, y);
val[i] = (2*n+1)*x + y;
v.push_back(val[i]);
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
for(int i=1;i<=n;i++) {
val[i] = lower_bound(v.begin(), v.end(), val[i])-v.begin()+1;
}
mp.clear();
LL sum1, sum2;
LL ans=0;
for (int i=1;i<=n;i++) {
sum1 = 0, sum2 = 0;
for(int j=1;j<=n;j++) {
sum1 += k1[val[j]];
sum1 %= MOD1;
sum2 += k2[val[j]];
sum2 %= MOD2;
}
mp[sum1*MOD2 + sum2] ++;
for(int j=i+1;j<=n;j++) {
sum1 += k1[val[j]]-k1[val[j-i]];
sum1 = (sum1%MOD1+MOD1)%MOD1;
sum2 += k2[val[j]]-k2[val[j-i]];
sum2 = (sum2%MOD2+MOD2)%MOD2;
mp[sum1*MOD2+sum2] ++;
}
for (auto x: mp) {
LL v = x.second;
ans += v * (v - 1) / 2;
}
mp.clear();
}
printf("%lld
", ans);
}
}
G
题意
修改最少的元素,使得序列的GCD为x,LCM为y。
题解
先判-1
(一番激烈的讨论)
如果a[i]%x!=0 or y%a[i]!=0
,那么i
就是个卜。
直觉告诉我们把一个数字变成x,另一个数字变成y,只要其它的数字不卜,生活就有保障了。
- 如果卜的个数>=2,那么答案就是卜的个数了。
- 否则答案可能是1,可能是2,可能是0
- 答案是0,很简单。
- 答案是1,很不简单。我们枚举一下每个数字,看他是否能力挽狂澜,我们把枚举的数字放逐掉,求出其它数字的GCD&LCM(先预处理前缀后缀GCD&LCM),然后看一看世界末日前怎么办?来得及拯救吗?【具体怎么做,留给读者思考。】
- 答案是2,很简单,加个else
I
题意
n堆石头,两种操作,两人轮流操作。
- 可以从一堆石头中拿走一个石头。
- 如果每堆石子都至少有1个,可以从每堆石头中拿走一个石头。
先手胜?后手胜?
题解
冷静分析一下
- n%2=1. 易证,留给读者思考【读者似乎就我一个人。】
- n%2=0. 这个得冷静分析一下。
- min=1, 先手可以把后手气死。类似于chomp Game的模型。
- min=2, 第一种操作肯定不可以施展的!不然会被气死。既然只能施展第二种操作,胜负显而易见了吧。
- min=3, 先手可以把后手气死。类似于chomp Game的模型。
- min=4, .......
博弈在模型的直觉很重要的吖!这题意识到了chomp Game就很简单了吧。
K
题意
n个点,n条边,多组查询,求两点间最短路。
题解
先去掉一条边edge,那么这个图就是一颗树了。
枚举,u到v是否要经过edge即可。
冷静分析一下中期
- 先用了10min施展G,施展了一大半,然后咕咕咕了。
- 先用了10min施展B题。没考虑清楚自己在hash什么东西,耽误了一段时间,然后
WA11
。 - 用了13min过了K。
- 用了3min过了G的样例,
WA2
- 开始unlimited Fix G,中间用了很长一段时间次饭去了。但调G的时间至少有1小时。
- Bug1:没读完就输出结果,WA
- Bug2:复杂度
nsqrt(n)
.【不错,有创意】 - Bug3:
n=1
的特判不到位,搞得后面越界了。一大波RE。
- 用了一个小时Fix B题的Hash,好不容易开始双hash然后MLE。枚举长度后清空,解决了问题。
- 用了半个小时搞I
emmmm....大部分时间都在Fix辣鸡。。。
考虑清楚再写啊······
羊肉粉丝汤弱鸡啊。
感觉30min
4题,2h30min
8题是比较合理的。