0%

思路讲解

子序列自动机,最重要的是next数组,可以找到从i位置开始,字符下一次出现在哪个位置(下标)(包括i位置)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct seqAuto{	// 子序列自动机 subsequence automaton 
// 可以处理大小写字母,数字,但是可能要改一下base以及next
vector<vector<int>> next;
// 从i位置开始,字符下一次出现在哪个位置(下标)(包括i位置)
char base='a';
seqAuto(const string &s){
next.assign(SZ(s)+5,vector<int>(28,-1));
ROF(i,SZ(s)-1,0){
FOR(j,0,26){
next[i][j]=next[i+1][j];
}
next[i][s[i]-base]=i;
}
}
inline bool isFind(const string &s){ // 传入substr时,必须为const属性
ll idx=0;
FOR(i,0,SZ(s)-1){
if(next[idx][s[i]-base]!=-1){
idx=next[idx][s[i]-base]+1;
}else{
return false;
}
}
return true;
}
};

然后用双指针方式枚举子串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FOR(i,0,SZ(S)-1){	// 双指针
FOR(j,bp,SZ(S)){
assert(j>=i);
ll len=j-i;
if(!sat.isFind(S.substr(i,len))){ // pos,len
bp=j;
if(ans.empty() || len-1>SZ(ans.back())){
ans.clear();
ans.pb(S.substr(i,len-1));
}else if(len-1==SZ(ans.back()) ){
ans.pb(S.substr(i,len-1));
}
break;
}
}
}

AC代码

https://www.luogu.com.cn/record/218545124

心路历程(WA,TLE,MLE……)

思路讲解

使用递推方法加快Sum预处理速度。

image

递推代码。

1
2
3
4
5
6
7
8
ROF(k,log2(N)-1,0){  // 
FOR(i,0,pow2[k]-1){
// assert(pow2[k]+i<SZ(Sum[k+1]));
Sum[k][i]=Sum[k+1][i]+Sum[k+1][pow2[k]+i];
Sum[k][i]%=mod;
Cnt[k][i]=Cnt[k+1][i]+Cnt[k+1][pow2[k]+i];
}
}

AC代码

https://www.luogu.com.cn/record/218505364

心路历程(WA,TLE,MLE……)

赛时因为没有采用递推所以代码比较慢。

思路讲解

赛时稍微有点暴力,其实这个是增长的,递增的(不要从代数上想,从几何的角度想就容易很多)。

那么二分或者是双指针都行,那我们就写一个双指针吧,好久没写了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 双指针做法
FOR(i,1,N-1){
FOR(j,bp,N){
ll curArea=Sum[j-1]-Sum[i-1];
ll ldiff=Sum[N]-curArea*2; // ldiff不能加abs,只要ldiff变为负数了,继续加j一定会变大
if(ldiff>=0){
ans=min(ans,abs(ldiff));
}else{
ans=min(ans,abs(ldiff));
bp=j;
break;
}
}
}

核心做法如上,最重要的就是ldiff不能加abs,只要 ldiff 变为负数了,继续加 j 一定会变大(绝对值)。

AC代码

https://www.luogu.com.cn/record/218460139

心路历程(WA,TLE,MLE……)

https://www.luogu.com.cn/record/218309162

赛时TLE,也骗到了80分,可以了可以了。

思路讲解

和这道题目比较像,但又不完全一样。

CF-1011-D. Serval and Kaitenzushi Buffet

套路那比较像,但不完全一样。

其实最重要的就是要找到一个贪心结构,我们这边发现,倒过来遍历,然后一直选左括号,一旦右括号不够了,这个时候就要选一个左括号变为右括号。又因为前面的左括号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	ROF(i,N-1,1){
ans+=A[i];
pq.push(i);
balance--;
if(balance<0){ // 倒过来遍历,结果发现右括号数量不够了,这个时候必须牺牲一个左括号了
ans-=A[pq.top()];
// #ifdef LOCAL
// debug(pq.top());
// debug(A[pq.top()]);
// #endif
pq.pop();
balance+=2;
}
}

AC代码

https://atcoder.jp/contests/abc407/submissions/66140638

心路历程(WA,TLE,MLE……)

思路讲解

其实还是比较简单的,就是如果说最后的答案不涉及这个顺序问题,其实是可以不用管这个顺序的。

当然,所有选择的可能都是要管的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 选择1:不放多米诺骨牌,跳过当前格子
vis[i][j] = true;
dfs(covered_xor);
vis[i][j] = false;

// 选择2:尝试垂直放置多米诺骨牌 (向下)
if (i + 1 <= N && !vis[i + 1][j]) {
vis[i][j] = vis[i + 1][j] = true;
dfs(covered_xor ^ A[i][j] ^ A[i + 1][j]);
vis[i][j] = vis[i + 1][j] = false;
}

// 选择3:尝试水平放置多米诺骨牌 (向右)
if (j + 1 <= M && !vis[i][j + 1]) {
vis[i][j] = vis[i][j + 1] = true;
dfs(covered_xor ^ A[i][j] ^ A[i][j + 1]);
vis[i][j] = vis[i][j + 1] = false;
}

AC代码

https://atcoder.jp/contests/abc407/submissions/66113167

心路历程(WA,TLE,MLE……)