0%

思路讲解

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

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

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……)

思路讲解

image

首先,拿到题目,发现为01串,这个时候就要想到分块思想。

image

如何选用乘法压缩石块那?更优解。让B作为首位。但这种情况必须后面有A(即 idx≥3)。

image

最后代码实现就是这样

1
2
3
4
5
6
7
if(idx==1){
cout<<1<<"\n";
}else if(idx==2){
cout<<1+min(SZ(g[st[2]-'A']),3)<<"\n";
}else{
cout<<2<<"\n";
}

AC代码

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

思路讲解

从这道题目过来的。

ABC-402-E - Payment Required(酷似背包的状压dp)

其实还是有挺多不大一样的地方。

参考这篇题解。

https://www.luogu.com.cn/article/8f5nvjkq

这个主要难度还是在怎么样理解这个倒序遍历上面。

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
for(int k=K;k>=1;--k){	// 倒过来枚举,因为正过来不一定有合法转移
for(int s=0;s<(1<<N);++s){ // s为获得的宝物清单
for(int idx=1;idx<=N;++idx){ // idx为这一轮获得的宝物编号
ll idx_=idx-1;
bool canTran=true;
FOR(i,0,SZ(g[idx])-1){
if((s|(1<<(g[idx][i]-1)) ) == s){ // | 以后没起作用说明s里包括了
canTran=true;
}else{ // 如果前提条件中有东西是不存在在
canTran=false;
break;
}
}
if(canTran){
dp[k][s]+=max(dp[k+1][s|(1<<idx_)]+scr[idx],
dp[k+1][s]);
}else{
// 相当于白获得了。
dp[k][s]+=dp[k+1][s];
}
}
dp[k][s]/=N;
}
}
cout<<setprecision(6)<<fixed<<dp[K][0]<<"\n";

不过我们也可以作死,试一试正序遍历,其实也没有什么太大问题。

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

那么如何理解dp[K][0]是

AC代码

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

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