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 中国大陆许可协议进行许可。

posted @   冬天的睡袋  阅读(14)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起