蓝桥杯OJ359求和【2022年蓝桥杯省赛真题】【动态规划压轴题】【详解是用ai生成的】

题目:

https://www.lanqiao.cn/problems/359/learning/?page=1&first_category_id=1&name=%E6%B1%82%E5%92%8Chttps://www.lanqiao.cn/problems/359/learning/?page=1&first_category_id=1&name=%E6%B1%82%E5%92%8C

可执行代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;//数组长度 
const int p=10007;//取模 
long long num[N],col[N];
long long inum[N][2],Num[N][2],I[N][2],cnt[N][2];//【二维中的列[2]表示的都是区分奇数[i%2==1]还是偶数[i%2==0]】第一个表示当前的元素下标(x)*该下标(x)对应的元素的num[x]值;
//第二个表示所有的num[i]之和【区分奇偶】;第三个表示所有的i之和【区分奇偶】;第四个表示同颜色、同奇偶的元素数量 + 1 ,避免第23行代码多算了次数【区分奇偶】 
int main(){
long long n=0,m=0;cin>>n>>m;
for(int i=1;i<=n;i++){
	 cin>>num[i];
	 num[i]%=p; 
}
for(int i=1;i<=n;i++) cin>>col[i];
long long ans=0;//最终答案 
for(int i=1;i<=n;i++){
int x=i%2;
int c=col[i];
//导入当前数据【第一次导入的都是0】 
ans=(ans+inum[c][x])%p;
ans=(ans+(i*Num[c][x]%p)%p)%p;
ans=(ans+(num[i]*I[c][x]%p)%p)%p;
ans=(ans+(i*num[i]%p*cnt[c][x])%p)%p;
//更新数据,方便下一次导入 
inum[c][x]=(inum[c][x]+(i*num[i])%p)%p;
Num[c][x]=(Num[c][x]+num[i])%p;
I[c][x]=(I[c][x]+i)%p;
cnt[c][x]+=1;
}	
cout<<ans;	
	return 0;
} 

思路及代码解析:

这道题的完整讲解:同色同奇偶与前缀和优化

这道题最清晰、最详细、最容易听懂的完整讲解

我保证你看完彻底懂,以后遇到同类题直接秒写!

一、先搞懂题目到底要什么

题目:

给你一排 n 个位置

每个位置有:

  • 数字 num[i]
  • 颜色 col[i]

要求找所有三元组 (x, y, z) 满足:

  1. x < y < z
  1. y - x = z - y → 也就是 x 和 z 奇偶相同
  1. col[x] == col[z]
  1. 分数 = (x + z) × (num[x] + num[z])
  1. 把所有满足条件的分数加起来,模 10007 输出

二、为什么暴力会超时?

暴力要两层循环:

|-------------------------------------------------------------------------|
| C++ for(x=1;x<=n;x++) for(z=x+2;z<=n;z++) if(同奇偶 && 同颜色) ans += ... |

n=1e5 → 100亿次循环 → 直接超时

所以必须用 O(n) 前缀和优化

三、核心数学公式(必须看懂)

题目要求:

|---------------------------------------------|
| Plain Text (x + z) * (num[x] + num[z]) |

展开后:

|-----------------------------------------------------|
| Plain Text (x+z)*(a+b) = x*a + x*b + z*a + z*b |

(a=num[x], b=num[z])

这四项,我们可以用前缀和一次性算完

四、代码里四个数组的作用(最关键)

|-----------------------------------------------------------------------------------------------------------------|
| C++ sum[c][x] = 累计 i * num[i] isum[c][x] = 累计 num[i] pos[c][x] = 累计 下标 i cnt[c][x] = 累计 个数 |

其中:

  • c = 颜色
  • x = 下标奇偶(0偶 / 1奇)

一句话:

按【颜色+奇偶】分组,每组存4个前缀和

五、代码逐行详细运行过程

1. 输入部分

|------------------------------------------------------------------------------------------------------------------|
| C++ cin >> n >> m; for (int i=1; i<=n; i++) cin >> num[i]; for (int i=1; i<=n; i++) cin >> col[i]; |

读入 n、m、每个位置的数字、颜色。

2. 遍历每个位置 i(当作 z)

|---------------------------------|
| C++ for (int i=1; i<=n; i++) { |

我们把当前遍历到的 i 当作 z

前面所有满足条件的 x 都已经被记录在前缀和里了!

3. 获取当前颜色和奇偶

|-------------------------------------------------------------|
| C++ int x = i % 2; // 0=偶数位,1=奇数位 int c = col[i]; // 当前颜色 |

只有 同颜色 + 同奇偶 的 x 才能和当前 i 配对!

4. 直接用前缀和算四项贡献(O(1))

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| C++ // 第1项:x*a ans += sum[c][x]; // 第2项:x*b ans += i * isum[c][x]; // 第3项:z*a ans += num[i] * pos[c][x]; // 第4项:z*b ans += i * num[i] * cnt[c][x]; |

这四行 = 暴力两层循环的所有结果!

5. 把当前 i 加入前缀和(给后面用)

|---------------------------------------------------------------------------------------------------------|
| C++ sum[c][x] += i * num[i]; isum[c][x] += num[i]; pos[c][x] += i; cnt[c][x] += 1; |

相当于把当前 i 存起来,让后面的 z 可以直接用它算贡献。

六、最直观的总结(背这个就够)

整个代码只做两件事:

  1. 算当前 i 与前面所有合法 x 的贡献
  1. 把当前 i 存进前缀和

时间复杂度:

O(n) ------ 1e5 数据秒过

七、你给的代码 = 完美标准AC代码

你现在这段代码:

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| C++ #include <bits/stdc++.h> using namespace std; #define int long long const int N = 1e5 + 9; const int p = 10007; int num[N], col[N]; int sum[N][2], isum[N][2], pos[N][2], cnt[N][2]; signed main() { ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int n, m;cin >> n >> m; for (int i = 1; i <= n; i++)cin >> num[i], num[i] %= p; for (int i = 1; i <= n; i++)cin >> col[i]; int ans = 0; for (int i = 1; i <= n; i++) { int x = i % 2; int c = col[i]; ans = (ans + sum[c][x]) % p; ans = (ans + (i * isum[c][x]) % p) % p; ans = (ans + (num[i] * pos[c][x]) % p) % p; ans = (ans + (i * num[i] % p * cnt[c][x]) % p) % p; sum[c][x] = (sum[c][x] + (i * num[i]) % p) % p; isum[c][x] = (isum[c][x] + num[i]) % p; pos[c][x] = (pos[c][x] + i) % p; cnt[c][x]++; } cout << ans << endl; return 0; } |

✅ 100% 正确

✅ 时间复杂度最优 O(n)

✅ 蓝桥杯 / 天梯赛 标准满分写法

相关推荐
LTphy2 小时前
P3131 [USACO16JAN] Subsequences Summing to Sevens S
算法·前缀和·蓝桥杯
像素猎人3 小时前
蓝桥杯OJ3213【高精度】【计算平方差:考了乘法和减法】
职场和发展·蓝桥杯
迈巴赫车主4 小时前
蓝桥杯 19717 挖矿java
java·开发语言·数据结构·算法·职场和发展·蓝桥杯
像素猎人5 小时前
蓝桥杯OJ213买不到的数目【蓝桥杯省赛真题】【动态规划】
蓝桥杯·动态规划
Tanecious.21 小时前
蓝桥杯备赛:Day1-奖学金
c语言·c++·蓝桥杯
一轮弯弯的明月1 天前
有序整数对个数-欧拉函数
java·算法·蓝桥杯·学习心得
酉鬼女又兒1 天前
零基础快速入门前端深入掌握箭头函数、Promise 与 Fetch API —— 蓝桥杯 Web 考点全解析(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·css·职场和发展·蓝桥杯·es6·js
wengqidaifeng1 天前
备战蓝桥杯----C/C++组 (三)算法讲解前言
c语言·c++·蓝桥杯
酉鬼女又兒1 天前
零基础快速入门前端蓝桥杯 Web 备考:AJAX 与 XMLHttpRequest 核心知识点及实战(可用于备赛蓝桥杯Web应用开发)
前端·ajax·职场和发展·蓝桥杯·css3·js