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