我超 好jian的t宝
今天也没有看到jls登顶www
一些小理解:dp就是用集合来概括 这样就可以用递推的方式来最优解优化
而dp的状态自然千奇百怪 可谓条条大路
想的区间dp 单调队列就是i~j之间的max
但是无奈区间dp 我不会空间优化
那寄了 没想到可以用前缀和 我们维护一个m的滑动窗口即可
然后要注意的就是 我们最开始要加入下标0 因为这个也是一个合法的下标(我们维护的
是前面长度为m的区间
然后就是标号要大于m才 pop_front 始终记得我们维护的是前面长度为m的滑动窗口
这样前缀和就直接是不用减一的
这里解释一下为什么不用常用的前缀和-1的写法
因为我们维护的单调队列和求的东西要有直接关系 要是我们这边球的是-1 那么维护的也应该是-1
那么为什么不久直接维护0 0 呢
- #include
- using namespace std;
- const int N = 3e5+10;
- const int M = 1<<12;
- //const int mod = 1e9+7;
- #define int long long
- #define LL long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int n,m,s[N];
- signed main(){
- fast
- cin>>n>>m;
- int ans=-2e9;
- for(int i=1;i<=n;i++){
- cin>>s[i];
- ans=max(ans,s[i]);
- s[i]+=s[i-1];
- }
- deque<int>dq;//维护一个上升队列
- dq.push_back(0);
- for(int i=1;i<=n;i++){
- while(!dq.empty()&&s[dq.back()]>=s[i])dq.pop_back();
- dq.push_back(i);
- while(!dq.empty()&&i-dq.front()>m)dq.pop_front();
- if(!dq.empty()&&dq.front()-i)ans=max(ans,s[i]-s[dq.front()]);
- }
- cout<
- return ~~(0^_^0);
- }
1087. 修剪草坪
成功把自己绕进去了 哈哈
其实最开始就写对了 但是back 写成 front 以为自己思路出了问题
其实不是啊
我们最开始会想到二维的一个状态表示 f[i][j]表示第i个并且已经连了j个
可是这个确实是找不到啥单调性
那我们可以思考变成一维的情况 f[i]表示第i个并且合法的方案
那状态计算自然就出来了
f[i]=max(f[i-1],f[i-j-1]+s[i]-s[i-j]) (0<=j<=m)
我们把s[i]提出来 max{f[i-j-1]-s[i-j]} 这个的意思就是前面长度为m的滑动窗口中的max值
故可以用单调队列优化 为啥不把s[i]放进去 其实s[i]是一个实时的东西枚举到每一位s[i]就是那个
让后还要考虑的就是i可能和j 相等 是什么情况?
就相当与是一个长度为j+1的线段的和 就是0+s[i]-s[0] 即可 所以我们要设所有f[-1]变成0
- #include
- using namespace std;
- const int N = 1e5+10;
- const int M = 1<<12;
- //const int mod = 1e9+7;
- #define int long long
- #define LL long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int f[N],s[N];
- LL g(int i){
- return f[i-1]-s[i];
- }
- signed main(){
- fast
- int n,m;cin>>n>>m;
- for(int i=1;i<=n;i++){
- cin>>s[i];
- s[i]+=s[i-1];
- }
- deque<int>dq;//下降
- dq.push_back(0);
- for(int i=1;i<=n;i++){
- while(!dq.empty()&&(f[i-1]-s[i])>=(f[dq.back()-1]-s[dq.back()]))dq.pop_back();
- dq.push_back(i);
- while(!dq.empty()&&i-dq.front()>m)dq.pop_front();
- f[i]=max(f[i-1],f[dq.front()-1]-s[dq.front()]+s[i]);
- }
- cout<
- return ~~(0^_^0);
- }
1088. 旅行问题
拆成链都知道把
前缀和也要处理是吧
但是这么想 能让我们是线性的做法呢 其实也不是很难想啊
我们只要让每个区间的前缀和都大于0 就可以了
s[j]-s[i]>=0 (i<=j<=i+n)
然后就是模板了
但是这道题让我们正着反着只要一边可以就算可以
但是反向时应该是 o[i]-d[i-1] 这是一个坑点
- #include
- using namespace std;
- const int N = 2e6+10;
- const int M = 1<<12;
- //const int mod = 1e9+7;
- #define int long long
- #define LL long long
- #define endl '\n'
- #define Endl '\n'
- #define _ 0
- #define inf 0x3f3f3f3f3f3f3f3f
- #define fast ios::sync_with_stdio(false);cin.tie(nullptr);
- int s[N],o[N],d[N];
- bool ans[N];
- signed main(){
- fast
- int n;cin>>n;
- for(int i=1;i<=n;i++){
- cin>>o[i];
- o[i+n]=o[i];
- cin>>d[i];
- d[i+n]=d[i];
- }
- for(int i=1;i<=n<<1;i++){
- s[i]+=(o[i]-d[i])+s[i-1];
- }
- deque<int>dq;//min
- for(int i=n<<1;i>=1;i--){
- while(!dq.empty()&&s[i]<=s[dq.back()])dq.pop_back();
- dq.push_back(i);
- while(!dq.empty()&&dq.front()-i>n)dq.pop_front();
- if(!dq.empty()&&s[dq.front()]-s[i-1]>=0)ans[i]=true;
- }
- dq.clear();
- d[0]=d[n];
- for(int i=1;i<=n<<1;i++){
- s[i]=0;
- s[i]+=(o[2*n-i+1]-d[2*n-i])+s[i-1];
- }
- for(int i=n<<1;i>=1;i--){
- while(!dq.empty()&&s[i]<=s[dq.back()])dq.pop_back();
- dq.push_back(i);
- while(!dq.empty()&&dq.front()-i>n)dq.pop_front();
- if(!dq.empty()&&s[dq.front()]-s[i-1]>=0)ans[n-i+1]=true;
- }
- for(int i=1;i<=n;i++){
- if(ans[i])cout<<"TAK"<
- else cout<<"NIE"<
- }
- return ~~(0^_^0);
- }
-
相关阅读:
T507修改分区方法-Linux、Android系统适用
UE5实现相机水平矫正
【外汇天眼】携手共护外汇投资:2023年WikiFX晚宴首次在越南圆满举行
科技资讯|Vision Pro头显无损音频仅限USB-C AirPods Pro 2耳机
微信公众号根据关键词取文章列表 API
Vue3初始化加载loading
羧基荧光素-氨基.盐酸盐,FAM-NH2.HCl,138589-19-2
94. 二叉树的中序遍历(Swift实现, 迭代)
Java(一)--- DOS,文档注释,代码规范
Flutter中 ElevatedButton取代RaisedButton
-
原文地址:https://blog.csdn.net/qq_23852555/article/details/126090269