思路:1.可以使用懒标记线段树进行区间修改和查询,但是这样写不够萌新。
2. 使用二分 + 前缀和的思想解决。二分体现在二分答案,即去寻找最小的订单个数使教室无法安排。具体的,在每次check时,使用一个数组b来维护,对于区间[s,t],令b[s] += d表示从s天开始每天多用d 个,b[t+1] -= d表示第t+1条把这d个释放掉。然后利用前缀和便可以得知每天需要的教室数目,与a对比即可。时间复杂度O(nlogm),代码如下:
#include <bits/stdc++.h> typedef long long ll; const int N = 1e6+10; ll a[N], b[N]; std::array<int,3> all[N]; int n, m; void solve() { std::cin >> n >> m; for(int i=1;i<=n;i++) std::cin >> a[i]; for(int i=1;i<=m;i++) { int d, t, s; std::cin >> d >> s >> t; all[i] = {d,s,t}; } int l = 1, r = m+1; while(l<r) { int mid = (l+r)>>1; auto check = [&](int x) { memset(b,0,sizeof b); for(int i=1;i<=std::min(x,m);i++) { auto [d,s,t] = all[i]; b[s] += d, b[t+1] -= d; } for(int i=1;i<=n;i++) b[i] += b[i-1]; for(int i=1;i<=n;i++) if(b[i]>a[i]) return true; return false; }; if(check(mid)) r = mid; else l = mid+1; } if(r==m+1) std::cout << 0 << "\n"; else std::cout << -1 << "\n" << l << "\n"; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(0); int t = 1; while(t --) solve(); return 0; }E 带路
思路:题目数据范围有误,M,N 实际上是小于等于50的,所以我们直接进行暴力dfs求解。下面贴上了代码,数组mp是用于存储图形,vis则是记忆化数组,用于标记这个点是否到过,dir数组则是每个位置可能移动的四个方向:上下左右。在dfs过程中,我们需要注意判别边界和这个点是否已经到过。需要注意每次遇到.需要把记忆化数组重新初始化。
#include<bits/stdc++.h> using namespace std; char mp[55][55]; int vis[55][55]; vector<int> ans; int m,n; int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}}; void dfs(int x,int y,int deep){ int cnt = 0; for(int i = 0;i < 4;i ++){ int dx = x + dir[i][0],dy = y + dir[i][1]; if(dx >= 0 && dx <= m && dy >=0 && dy <=n && vis[dx][dy] == 0 && mp[dx][dy] == '.'){ vis[dx][dy] = 1; dfs(dx,dy,deep + 1); vis[dx][dy] = 0; cnt ++; }else{ ans.push_back(deep); } } if(cnt == 0) return; } void solve() { cin >> m >> n; for(int i = 0;i < m;i ++) for(int j = 0;j < n;j ++) cin >> mp[i][j]; for(int i = 0;i < m;i ++){ for(int j = 0;j < n;j ++){ if(mp[i][j] == '.'){ memset(vis,0,sizeof(vis)); vis[i][j] = 1; dfs(i,j,1); } } } sort(ans.begin(),ans.end()); cout << ans.back() << endl; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(0); int t = 1; //cin >> t; while(t --) solve(); return 0; }
K 质量检测
思路:滑动窗口模板题,思想类似于双指针,滑动窗口详解 - 知乎 (zhihu.com)。时间复杂度O(n)。也可以使用ST表等方法。
#include<bits/stdc++.h> using namespace std; deque<int> q; void solve() { int n,m;scanf("%d %d",&n,&m); vector<int> a(n+1); for(int i = 1;i <= n;i ++) scanf("%d",&a[i]); for(int i = 1;i <= n;i ++){ while(!q.empty() && a[q.back()] > a[i]) q.pop_back(); q.push_back(i); if(i >= m){ while(!q.empty() && q.front() <= i - m) q.pop_front(); printf("%d\n",a[q.front()]); } } return ; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(0); int t = 1; //cin >> t; while(t --) solve(); return 0; }