【蓝桥杯逐日一题】3.25

[复制链接]
发表于 2025-10-9 20:43:46 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
 

🏝️专栏: 【蓝桥杯备篇】
🌅主页: f狐o狸x

“OJ超时不是尽头,是算法在提示你该优化时间复杂度了!”


目次

3.25 差分数组
一、一维差分
        标题链接:
        标题形貌:
        解题思绪:
        解题代码:
二、海底高铁
        标题链接:
        标题形貌:
        解题思绪:
        解题代码:
三、二维差分
        标题链接:
        标题形貌:
        解题思绪:
        解题代码:
四、地毯
        标题链接:
        标题形貌:
        解题思绪:
        解题代码:

3.25 差分数组

        我们直接用一道题来相识差分数组吧
一、一维差分

        标题链接:

        【模板】差分
        标题形貌:


        解题思绪:

        照旧可以用暴力摆列来搞定,我们把整个数组遍历一遍,再把对应位置加上x就行了,但是如许绝对是会超时长滴,否则我干嘛用这个例题?
        对于类似的题,我们就可以用差分算法,和前缀和数组类似,我们必要预处理惩罚一个差分数组出来

        这个数组的利益就是当你要在 l ~ r 的区间加上 x 的时间(图中用2~5)来表现,就只必要在差分数组中的 l 位置加上 x ,r + 1 位置减去 x ,再还原为原数组就行

            也就是:a[ l ] += x; a[ r + 1 ] -= x;
          此时尚有人要问:煮波煮波,那怎么还原数组呢?着实把差分数组做一个前缀和运算即可还原 证明如下:


        解题代码:

  1. #include <iostream>
  2. using namespace std;
  3. typedef long long LL;
  4. const int N = 1e5 + 10;
  5. LL a[N];
  6. int n, m;
  7. int main()
  8. {
  9.     cin >> n >> m;
  10.     // 利用差分的性质预处理差分数组
  11.     for(int i = 1; i <= n; i++)
  12.     {
  13.         LL x;cin >> x;
  14.         a[i] += x;
  15.         a[i + 1] -= x;
  16.     }
  17.     // m次操作
  18.     while(m--)
  19.     {
  20.         LL l, r, x; cin >> l >> r >> x;
  21.         a[l] += x;
  22.         a[r + 1] -= x;
  23.     }
  24.     // 利用前缀和还原数组
  25.     for(int i = 1; i <= n; i++)
  26.     {
  27.         a[i] = a[i - 1] + a[i];
  28.         cout << a[i] << " ";
  29.     }
  30.    
  31.     return 0;
  32. }
复制代码
二、海底高铁

        标题链接:

        P3406 海底高铁
        标题形貌:


        解题思绪:

        这里我们只必要知道这个人每段铁路一共坐了反复,再判断是直接买票划算照旧买卡划算,末了累加输出即可
        解题代码:

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 1e5 + 10;
  4. typedef long long LL;
  5. LL f[N];
  6. int n, m;
  7. int main()
  8. {
  9.         cin >> n >> m;
  10.         int l, r; cin >> l;
  11.         // 利用差分记录每段铁路经过的次数
  12.         for (int i = 2; i <= m; i++)
  13.         {
  14.                 cin >> r;
  15.                 if (l <= r) f[l] += 1, f[r] -= 1;
  16.                 else f[r] += 1, f[l] -= 1;
  17.                 l = r;
  18.         }
  19.         // 还原数组
  20.         for (int i = 1; i <= n; i++)
  21.         {
  22.                 f[i] = f[i - 1] + f[i];
  23.         }
  24.         LL ret = 0;
  25.         for(int i = 1; i < n; i++)
  26.         {
  27.                 LL a, b, c; cin >> a >> b >> c;
  28.                 ret += min(a * f[i], c + b * f[i]);
  29.         }
  30.         cout << ret << endl;
  31.         return 0;
  32. }
复制代码
三、二维差分

        标题链接:

        【模板】二维差分
        标题形貌:


        解题思绪:

        如图所示我们必要对以下结果数组举行利用:

   f[x1][y1] + k
  f[x2 + 1][y1] - k
  f[x1][y2 + 1] - k
  f[x2 + 1][y2 + 1] - k
           如许我们累加起来以后就可以得到二维数组中区间+k的利用
        解题代码:

  1. #include <iostream>
  2. using namespace std;
  3. typedef long long LL;
  4. const int N = 1010;
  5. LL f[N][N];
  6. int n, m, q;
  7. void insert(int x1, int y1, int x2, int y2, int x)
  8. {
  9.     f[x1][y1] += x;
  10.     f[x2 + 1][y1] -= x;
  11.     f[x1][y2 + 1] -= x;
  12.     f[x2 + 1][y2 + 1] += x;
  13. }
  14. int main()
  15. {
  16.     cin >> n >> m >> q;
  17.     // 预处理二维齐差分数组
  18.     for(int i = 1; i <= n; i++)
  19.     {
  20.         for(int j = 1; j <= m; j++)
  21.         {
  22.             LL a; cin >> a;
  23.             insert(i, j, i , j ,a);
  24.         }   
  25.     }
  26.     while(q--)
  27.     {
  28.         LL x1, y1, x2, y2, a; cin >> x1 >> y1 >> x2 >> y2 >>a;
  29.         insert(x1, y1, x2, y2, a);
  30.     }
  31.     for(int i = 1; i <= n; i++)
  32.     {
  33.         for(int j = 1; j <= m; j++)
  34.         {
  35.             f[i][j] = f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1] + f[i][j];
  36.             cout << f[i][j] << " ";
  37.         }
  38.         cout << endl;
  39.     }
  40.    
  41.     return 0;
  42. }
复制代码
四、地毯

        标题链接:

        P3397 地毯
        标题形貌:

        

        解题思绪:

        这题着实就是把地毯对应的地区全加上一,末了再输出数组即可办理
        解题代码:
 


  1. #include <iostream>
  2. using namespace std;
  3. const int N = 1010;
  4. int f[N][N];
  5. int n, m;
  6. void insert(int x1, int y1, int x2, int y2, int a)
  7. {
  8.         f[x1][y1] += a;
  9.         f[x2 + 1][y1] -= a;
  10.         f[x1][y2 + 1] -= a;
  11.         f[x2 + 1][y2 + 1] += a;
  12. }
  13. int main()
  14. {
  15.         cin >> n >> m;
  16.         while (m--)
  17.         {
  18.                 int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
  19.                 insert(x1, y1, x2, y2, 1);
  20.         }
  21.         for (int i = 1; i <= n; i++)
  22.         {
  23.                 for (int j = 1; j <= n; j++)
  24.                 {
  25.                         f[i][j] = f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1] + f[i][j];
  26.                         cout << f[i][j] << " ";
  27.                 }
  28.                 cout << endl;
  29.         }
  30.         return 0;
  31. }
复制代码
        本日就到这里吧,下一期我们将讲授二分算法~886~
        蓝桥杯选手一样寻常:
        睡醒→看题→看不懂→搜题解→抄代码→被卡常→怒删重写→提交→WA

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表