日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

基本算法之前缀和与差分的是使用

發布時間:2025/3/19 12 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基本算法之前缀和与差分的是使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前綴和與差分

  • 前綴和
    • 鳴謝
    • 二維前綴和
    • 激光炸彈
  • 差分
    • 求差分
    • 差分求區間修改
    • 增減序列
    • 最高的牛

前綴和

鳴謝

添加鏈接描述

添加鏈接描述

二維前綴和

激光炸彈

題目鏈接

解題思路:

解法思路:我們首先觀察題目,可以建立一個數組f[i][j]表示坐標為(xi,yj)(xi,yj)上的權值,那么我們接著思考,因為題目上面說了要求算出這個邊長為r的正方形面積,而且整個題目中,只有查詢操作,沒有修改操作,且內存只要略微省著用,就可以滿足O(n2)O(n2)的條件,所以我們可以確認這一題可以使用二維前綴和。

代碼:

#include<stdio.h> #include<algorithm> using namespace std; int n,r; int g[5010][5010];int main(){scanf("%d%d",&n,&r);r = min(5001,r); // 變了這里for(int i=1;i<=n;++i){int x,y,w;scanf("%d%d%d",&x,&y,&w);x++,y++;g[x][y] += w;}for(int i=1;i<=5001;++i)for(int j=1;j<=5001;++j)g[i][j] += g[i-1][j] + g[i][j-1] - g[i-1][j-1];int res = 0;for(int i=r;i<=5001;++i)for(int j=r;j<=5001;++j) res = max(res,g[i][j] - g[i][j-r] - g[i-r][j] + g[i-r][j-r]);printf("%d\n",res);return 0; }

差分

求差分

求出a 的差分序列 b ,b1=a1,bi=ai?ai?1(2<=i<=n)b_1 = a_1,b_i = a_i - a_{i-1} (2 <= i <= n)b1?=a1?,bi?=ai??ai?1?(2<=i<=n)

代碼:

// a 從下標一開始存 // 如果用原來的 數組求差分序列,要從后向前 求,因為要保留 a[i-1]for(int i = n ; i>1;--i)a[i] = a[i] - a[i-1];

差分求區間修改

把區間a[l ,r] 都加上一個 數 d;
b[l]+=d,b[r+1]+=db[l] += d , b[r+1] += d b[l]+=d,b[r+1]+=d

把區間a[l ,r] 都減去一個 數 d;
b[l]?=d,b[r+1]+=db[l] -= d , b[r+1] += d b[l]?=d,b[r+1]+=d

增減序列

題目鏈接

解題思路:

首先明確 將所有的數一樣大,那么從2~n的差分序列都為0,b[1] 可以不為0.都與b[1] 一樣即可。在操作的時候我們采取貪心的思路,因為每一次操作都是一正一負,至于為什么要是正負配對,因為我們是要這個B序列2~n都要為0,所以這樣負數增加,正數減少,就可以最快地到達目標為0的狀態。
至于那些無法配對的數BkBk可以選B1B1或者Bn+1Bn+1,這兩個不影響的數,進行修改。

因此最小操作次數為:
min(pos,neg)+abs(pos?neg)=max(pos,neg)min(pos,neg) + abs(pos-neg) = max(pos,neg)min(pos,neg)+abs(pos?neg)=max(pos,neg)
種類數:
abs(pos?neg)+1abs(pos -neg)+1abs(pos?neg)+1

代碼:

#include<stdio.h> #include<math.h> #include<algorithm> using namespace std;const int N = 1e5 + 10; typedef long long ll; int n; ll a[N]; ll psum,nsum; int main(){scanf("%d",&n);psum = nsum = 0;for(int i = 1;i<=n;++i)scanf("%lld",&a[i]);for(int i = n ; i>1;--i)a[i] = a[i] - a[i-1];for(int i = 2;i<= n ;++i)if(a[i] > 0)psum += a[i];else nsum -= a[i]; // 加負數的絕對值,那么直接減就好printf("%lld\n%lld\n",max(psum,nsum),abs(psum - nsum) + 1);return 0; }

最高的牛

題目鏈接

解題思路:

代碼:

#include<stdio.h> #include<stdlib.h> #include<map>using namespace std;const int N = 1e4 + 10; // 用map 和 pair 來記錄是否重復 map <pair<int ,int>,bool> vis; int a[N],b[N]; int n,p,h,m; int x,y; int main(){scanf("%d%d%d%d",&n,&p,&h,&m);for(int i=1;i<= m ;++i){scanf("%d%d",&x,&y);if(x>y)swap(x,y);if(vis[make_pair(x,y)])continue;b[x+1]-- , b[y]++ ; // 所以不能 x++vis[make_pair(x,y)] = 1; // 因為這里還要用到 x }for(int i=1;i<=n;++i){a[i] = a[i - 1] + b[i];printf("%d\n",h+a[i]);}return 0;}

總結

以上是生活随笔為你收集整理的基本算法之前缀和与差分的是使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。