8.14 (河南牛客萌新赛 线段树 ,ST求区间最值,迪杰斯特拉建正反图,bfs+二分,模拟)+状态bfs搜素
nowcoder
D区间问题1
线段树板子题(区间修改,单点查询)
#include<bits/stdc++.h>
#define maxn 1000010
#define mid ((l+r)>>1)
#define li i<<1
#define ri 1+(i<<1)
using namespace std;
int n,val[maxn];
struct Node{
int l,r,sum,k;
}tree[maxn];
void Read(){
cin >> n;
for(int i = 1;i <= n;i++)cin >> val[i];
}
void build(int i,int l,int r){
tree[i].l = l;
tree[i].r = r;
if(l == r){
tree[i].sum = val[l];
return ;
}
build(li,l,mid);
build(ri,mid+1,r);
tree[i].sum = tree[li].sum + tree[ri].sum;
return ;
}
void add(int i,int l,int r,int k){
if(l <= tree[i].l && tree[i].r <= r){
tree[i].k += k;
return ;
}
if(tree[li].r >= l)
add(li,l,r,k);
if(tree[ri].l <= r)
add(ri,l,r,k);
}
int search(int i,int dis,int ans){
if(tree[i].l == tree[i].r){
return val[dis] + tree[i].k;
}
if(dis <= tree[li].r)
return tree[i].k + search(li,dis,ans);
return tree[i].k + search(ri,dis,ans);
}
void interaction(){
int t;
cin>>t;
while(t--){
int tot;
cin >> tot;
if(tot == 2){
int dis;
cin >> dis;
cout << search(1,dis,0) << endl;
} else if(tot == 1){
int l,r,k;
cin >> l >> r >> k;
add(1,l,r,k);
} else if(tot == 3){
return ;
}
}
}
int main(){
Read();
build(1,1,n);
interaction();
return 0;
}
H区间问题2
ST求区间最值问题板子
#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 25
#define N 10000005
using namespace std;
int n,m;
int a[N],Log[N];
int f[N][M];
void GetLog()
{
int i;
Log[1]=0;
for(i=2;i<=n+1;++i)
Log[i]=Log[i/2]+1;
}
void RMQ()
{
int i,j;
for(i=1;i<=n;++i)
f[i][0]=a[i];
for(j=1;(1<<j)<=n;++j)
for(i=1;i+(1<<(j-1))<=n;++i)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int main()
{
int l,r,i,k,ans;
scanf("%d",&n);
for(i=1;i<=n;++i)
scanf("%d",&a[i]);
scanf("%d",&m);
GetLog();
RMQ();
for(i=1;i<=m;++i)
{
scanf("%d%d",&l,&r);
k=Log[r-l+1];
ans=max(f[l][k],f[r-(1<<k)+1][k]);
printf("%d\n",ans);
}
return 0;
}
I小美想打音游
思路是选中位数,然后依次计算每一个差值即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> scores(n);
for (int i = 0; i < n; ++i) {
cin >> scores[i];
}
sort(scores.begin(), scores.end());
int median = scores[n / 2];
long long total_magic = 0;
for (int score : scores) {
total_magic += abs(score - median);
}
total_magic += 1;
cout << total_magic << endl;
return 0;
}
F小美想跑步
我们只需要一个迪杰斯特拉,求两个距离,一个是从家到任意一个点的最小距离,
另一个是从任意一个点到家的最短距离,每次求和即可
#include <bits/stdc++.h>
using namespace std;
const int INF = INT_MAX;
vector<long long> dijkstra(int start, vector<vector<pair<int, int>>>& graph) {
int n = graph.size();
vector<long long> dist(n, INF);
priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;
dist[start] = 0;
pq.push({0, start});
while (!pq.empty()) {
int u = pq.top().second;
long long d = pq.top().first;
pq.pop();
if (d > dist[u]) continue;
for (auto& edge : graph[u]) {
int v = edge.first;
int weight = edge.second;
if (dist[u] + weight < dist[v]) {
dist[v] = dist[u] + weight;
pq.push({dist[v], v});
}
}
}
return dist;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<vector<pair<int, int>>> graph(n + 1);
vector<vector<pair<int, int>>> reverse_graph(n + 1);
for (int i = 0; i < m; i++) {
int x, y, z;
cin >> x >> y >> z;
graph[x].push_back({y, z});
reverse_graph[y].push_back({x, z});
}
vector<long long> dist_from_home = dijkstra(1, graph);
vector<long long> dist_to_home = dijkstra(1, reverse_graph);
long long ans = 0;
for (int i = 2; i <= n; i++) {
ans += dist_from_home[i] + dist_to_home[i];
}
cout << ans;
return 0;
}
K小美想游泳
已经图上从s到t的路有整个地图那么多,我们二分总距离,如果过程中距离大于二分值就不行,缩小
继续找,直到满足条件
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200010;
vector<pair<int, int>> graph[MAXN];
int n, m, s, t;
bool bfs(int limit) {
vector<bool> visited(n + 1, false);
queue<int> q;
q.push(s);
visited[s] = true;
while (!q.empty()) {
int curr = q.front();
q.pop();
if (curr == t) return true;
for (auto& edge : graph[curr]) {
int next = edge.first;
int weight = edge.second;
if (!visited[next] && weight <= limit) {
visited[next] = true;
q.push(next);
}
}
}
return false;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> m;
int max_weight = 0;
for (int i = 0; i < m; i++) {
int x, y, w;
cin >> x >> y >> w;
graph[x].push_back({y, w});
graph[y].push_back({x, w});
max_weight = max(max_weight, w);
}
cin >> s >> t;
int left = 0, right = max_weight;
while (left < right) {
int mid = left + (right - left) / 2;
if (bfs(mid)) {
right = mid;
} else {
left = mid + 1;
}
}
cout << left << endl;
return 0;
}
B学生分组
模拟一遍即可,先判断能不能操作,最小的数l,最大r,如果lxn>sum
or rxn<sum就不行,其他情况我们从左边把小于l的数的差取出来,还有大于r的数的差取出来,
我们取max即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6+10;
int n,l,r;
int a[N];
signed main() {
cin >> n;
int sum = 0;
for (int i = 1; i<= n; i++) {
cin >> a[i];
sum += a[i];
} cin >> l >> r;
if(l*n > sum || r*n < sum) {
cout << -1 << endl;
return 0;
}
int ans1 = 0;
int ans2 = 0;
for (int i = 1; i <= n; i++) {
if(a[i] < l) {
a[i] = l-a[i];
ans1 += a[i];
}
else if(a[i] > r) {
a[i] = a[i]-r;
ans2 += a[i];
}
else a[i] = 0;
}
cout << max(ans1,ans2) << endl;
return 0;
}
小学生爬楼梯
签到
#include <bits/stdc++.h>
using namespace std;
#define int long long
int mod= 1000000007;
int f[1008611];
int32_t main(){
int n;
cin>>n;
f[0]=0;
f[1]=1;
f[2]=2;
f[3]=4;
for(int i=4;i<=n;i++){
f[i]=(f[i-2]+f[i-1]+f[i-3])%mod;
}
cout<<f[n]%mod;
}
哥德巴赫猜想
签到
暴力即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
bool isPrime(int n) {
if (n <= 1) return false;
for (int i = 2; i <= sqrt(n); i++) {
if (n % i == 0) return false;
}
return true;
}
vector<int> findThreePrimes(int n) {
for (int i = 2; i <= n; i++) {
if (isPrime(i)) {
for (int j = i; j <= n; j++) {
if (isPrime(j)) {
int k = n - i - j;
if (k >= j && isPrime(k)) {
return {i, j, k};
}
}
}
}
}
return {};
}
int32_t main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> result = findThreePrimes(n);
if (!result.empty()) {
cout << result[0] << " " << result[1] << " " << result[2] << '\n';
}
}
return 0;
}
逃离迷宫
这道题和下面这个题基本一模一样但是存在一点区别
wyh的吃鸡
都是三维开状态,我一开始开了50个状态,这样会内存爆掉
我们其实只需要考虑两个状态有没有钥匙就行,每次走拿到钥匙也是会遍历整个图,
没有拿到钥匙也会遍历整个图,重点是没有拿到钥匙的经过K会改变当前的点状态,这个
时候K距离从没有钥匙转移到有钥匙,而前有钥匙的点经不经过后面的K没有影响
我们BFS出来的条件是最先找到K并且先到达终点的点,所以我们只需要判断走到终点有没有K即可return
没有找到return -1,即可
而吃鸡的题我们需要重复走,吃鸡的题开车会影响最终时间,不同的状态经过车最终的时间不同,是需要重复多跑的
逃离迷宫的代码如下
#include <bits/stdc++.h>
using namespace std;
#define int long long
char mp[501][501];
int dist[501][501][2];
int xx[]={0,0,1,-1};
int yy[]={1,-1,0,0};
int n,m;
int ex,ey;
int tx,ty;
bool vis[501][501][2];
struct node{
int x;
int y;
int road;
};
bool inmp(int x,int y){
return x>0&&x<=n&&y>0&&y<=m&& mp[x][y] != '#';
}
int bfs(int sx, int sy, int ex, int ey) {
memset(dist, -1, sizeof(dist));
queue<node> q;
q.push({sx, sy, 0});
dist[sx][sy][0] = 0;
while (!q.empty()) {
node cur = q.front();
q.pop();
if (cur.x == ex && cur.y == ey && cur.road) {
return dist[cur.x][cur.y][cur.road];
}
for (int i = 0; i < 4; ++i) {
int nx = cur.x + xx[i];
int ny = cur.y + yy[i];
int nroad = cur.road;
if (!inmp(nx, ny)) continue;
if (mp[nx][ny] == 'E' && !nroad) continue; // 不能穿过终点
if (mp[nx][ny] == 'K') {
nroad = 1;
}
if (dist[nx][ny][nroad] == -1) {
dist[nx][ny][nroad] = dist[cur.x][cur.y][cur.road] + 1;
q.push({nx, ny, nroad});
}
}
}
return -1;
}
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
cin>>n>>m;
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=m ; ++j) {
cin>>mp[i][j];
if(mp[i][j]=='E'){
ex=i,ey=j;
}else if(mp[i][j]=='P'){
tx=i,ty=j;
}
}
}
int result = bfs(tx, ty, ex, ey);
if (result == -1) {
cout << "No solution\n";
} else {
cout << result << '\n';
}
}
return 0;
}
本文作者:冬天的睡袋
本文链接:https://www.cnblogs.com/dontian/p/18360053
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步