CSP-S
Point
题目 | lock 密码锁 | game 消消乐 | struct 结构体 | tree 种树 |
---|---|---|---|---|
预估 | 100 | 35 | 100 | 0 |
实际 | 100 | 35 | 40 | 0 |
改题后 | 100 | 100 | 100 | 100 |
Problem
T 1 T1 T1 lock
题目大意
给出几个用同一把锁打乱后的五位密码(只打乱一位密码或连续两位密码,并保证与正确密码不同),问正确密码的方案数。
考场解法( O ( 81 n ) O(81n) O(81n))
由打乱后的密码“00000”为例,这个密码可以由81个密码得来:
-
只拨动一位: 9 × 5 = 45 9 \times 5 = 45 9×5=45 种(每位可能会拨1~9次)
-
波动两位: 9 × 4 = 36 9 \times 4 = 36 9×4=36 种(可能会拨1~9次,且只会拨动1、2或2、3或3、4或4、5位)
总结
继续保持吧。没什么好说的
T 2 T2 T2 game
题目大意
给出一个字符串,其中定义一个可消除的串为:
- 是一个连续的串
- 每次操作可以从字符串中删除两个相邻的相同字符,操作后剩余字符串会拼接在一起,若干次操作后这个串为空串。
询问有多少个子串为可消除的串
考场解法( O ( n 3 ) O(n^3) O(n3))
普通的区间 d p dp dp,枚举长度和起始点以及断点,然后不断更新。
正解( O ( n ) O(n) O(n))
这思路太妙了!
主体是一个字典树,读入过程可看作建一棵树。
对于一个可消除的串,栈插入开头前和插入结尾后的状态是一样的,于是可将它看成树,遇到向根走的边就往根上跳,否则往对应的边跳,并统计一下每种状态的次数,就能求出很容易算出答案。
Code
S[0]=1;//统计次数
now=cnt=0;//now:当前位置 cnt:trie的大小
for(int i=0;i<n;i++){
ch=s[i]-'a';//s为字符串
if(now&&!(pre[now]^ch))now=pre_to[now];//往上跳
else{
if(!trie[now][ch]){//建点
trie[now][ch]=++cnt;
pre[cnt]=ch;
pre_to[cnt]=now;
}
now=trie[now][ch];//往下跳
}
ans+=S[now];//统计答案
S[now]++;//统计次数
}
总结
要想一想“数形结合”!
T 3 T3 T3 struct
problem
考场失误点
忘记3操作最后的清空数组,导致挂掉 60 p t s 60pts 60pts(有3操作的分)。
反思
记得加上初始化
T 4 T4 T4 tree
题目大意
有n块地要种树,第 i i i个地所对应的树在第 x x x天可以长 m a x ( b i + c i ∗ x , 1 ) max(b_i+c_i*x,1) max(bi+ci∗x,1)个单位,一开始为0单位,要长到 a i a_i ai单位。前 n n n天可以在已种树的地相邻的地中一棵树,特殊的第1天只能中1号树。问最早什么时候可以使所有树生长到要求高度。
考场( O ( 1 ) O(1) O(1))
直接输出 n n n
正解( O ( n ∗ l o g 2 2 n ) O(n*log^2_2n^) O(n∗log22n))
首先在外部二分答案。
然后对于答案
x
x
x和第
i
i
i棵树,可以用二分去算出这棵树最晚何时种植才能满足在第
x
x
x天长度高于
a
i
a_i
ai,若这时间小于1,那么可以直接false
接着从小到大排序,对于一棵树i,要将i的所有祖先种植完才可以种植,然后再次判断
O
(
n
)
O(n)
O(n)
//d为栈,now_note为当前的树,top为栈的大小,vis为是否种过树,now为当前是第几个种的树
top=0;
now_note=s[i];
while(now_note&&!vis[now_note]){//寻找第一个种过树的祖先
d[++top]=now_note;
now_note=a[now_note].fa;
}
while(top){//从根往叶种植
now++;
vis[d[top]]=1;
top--;
}
if(now>a[s[i]].lst_time)return false;//判断是否超时
问题
时间并没有规划好,导致第四题最后5分钟才看题,没时间打
反思
规划好时间,要在有限的时间内得到更多的分数