8.14 (河南牛客萌新賽 線段樹 ,ST求區間最值,迪傑斯特拉建正反圖,bfs+二分,模擬)+狀態bfs搜素

冬天的睡袋發表於2024-08-15

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;
}

相關文章