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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数字串

發布時間:2023/12/3 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数字串 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

來源:牛客網:

題目描述

一個只含數字的字符串,q次操作,每次操作將第i位數字改為x,每次操作后,統計長度在[l, r]之間且首數字大于尾數字的子串的個數。

輸入描述:
第一行一個只含數字的字符串;
第二行3個整數q, l, r;
接下來q行,每行兩個整數i, x。
輸出描述:
輸出q行,每行一個整數,表示長度在[l, r]之間且首數字大于尾數字的子串的個數。
示例1
輸入
復制

585605 2 2 4 1 6 4 2

輸出
復制

7 8

備注:

設字符串長度為n則: 1 <= n <= 100000; 1 <= q <= 100000; 1 <= l <= r <= n; 1 <=
i <= n; 0 <= x <= 9;

題解:

題意很明確,可以用樹狀數組和線段樹來做
我用的樹狀數組,用到一個二維的數組,0~9的每個數組為一維,記錄的是該范圍內數組x出現的次數
雖然是二維數組sum[x][y],但其實大部分操作和一維樹狀數組是一樣的,因為數組sum中的x是給定的,只剩下一個y來變動
本題中有兩個操作,一個是修改數,一個是輸出結果
在每次輸出時我們要先將指定位置原來的數刪去,因為不這樣的話查詢新值的時候可能會把當前沒有更新的值算進去。即add(now,pos,-1)
在查詢結果的代碼中,會出現連續的四個for循環,我來講解一下:

for(int j = 0;j< now;j++)ans-= query(j,pos+l-1,pos+r-1);//包含第pos位的區間, for(int j = 0;j< x;j++)ans+= query(j,pos+l-1,pos+r-1);for(int j = now+1;j<= 9;j++)ans-= query(j,pos-r+1,pos-l+1);for(int j = x+1;j<= 9;j++)ans+= query(j,pos-r+1,pos-l+1);

要先記住一個條件:
我們要替代的位置是pos,該位置的數原本是now,要替換成x
題目要求統計長度在[l, r]之間且首數字大于尾數字的子串的個數
第一個for:因為now被替代了,那以now為首字母,以小于now的數為尾數子所構成的子串就不存在了,所以查詢區間[pos+l-1,pos+r-1]內小于now數的數量,這就是不存在的子串數。為什么區間是[pos+l-1,pos+r-1]呢?因為被代替的位置是pos,題目要求的是長度在[l, r]的子串,所以從pos往后l和r才是我們所要的區間
第二個for:正好與第一個相反,因為x的加入,所以以x為首字母,小于x的數為尾字母所構成的子串增加,所以要加上,就是上一個翻版
第三個for:因為now沒了,那以now為尾字母,以大于now的數為首字母的數所構成的子串也沒了,所以要減去
第四個for:是第三個for的翻版
總結一下:因為now的離開和x的加入,導致以now為首字母和以now為尾字母的情況不再存在,而以x為首字母和以x為尾字母的情況增加
最后記得:要把x加入到樹狀里

add(x,pos,1);

感覺講的足夠詳細了

代碼:

#include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) #define mod 1000000007 using namespace std; typedef long long ll; const int maxn = 2e5+5; const double esp = 1e-12; const int ff = 0x3f3f3f3f; map<int,int>::iterator it;int n,q,l,r; char s[maxn]; ll sum[11][maxn];int lowbit(int x) {return x&(-x); }ll get_sum(int num,int x)//計算區間和? {ll ans = 0;for(int i = x;i>= 1;i-= lowbit(i))ans+= sum[num][i];return ans; }ll query(int num,int l,int r) {if(l> n||r< 1) return 0;l = max(1,l);//注意細節r = min(n,r);return get_sum(num,r)-get_sum(num,l-1); }void add(int num,int x,int val)//更新num這個數的那一維? {for(int i = x;i<= n;i+= lowbit(i))sum[num][i]+= val; }int main() {scanf("%s",s+1);cin>>q>>l>>r;n = strlen(s+1);for(int i = 1;i<= n;i++)add(s[i]-'0',i,1);//更新樹狀數組?ll ans = 0;for(int i = 1;i<= n;i++)for(int j = 0;j< s[i]-'0';j++)ans+= query(j,i+l-1,i+r-1);//查詢 i+l-1,i+r-1之間比他小的數while(q--){int pos,x,now;scanf("%d %d",&pos,&x);now = s[pos]-'0';//被代替的數//x是替代的數 add(now,pos,-1);//注意要先減掉,因為不這樣的話查詢新值的時候可能會把當前沒有更新的值算進去for(int j = 0;j< now;j++)ans-= query(j,pos+l-1,pos+r-1);//包含第pos位的區間, for(int j = 0;j< x;j++)ans+= query(j,pos+l-1,pos+r-1);for(int j = now+1;j<= 9;j++)ans-= query(j,pos-r+1,pos-l+1);for(int j = x+1;j<= 9;j++)ans+= query(j,pos-r+1,pos-l+1);add(x,pos,1); s[pos] = x+'0';printf("%lld\n",ans);}return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的数字串的全部內容,希望文章能夠幫你解決所遇到的問題。

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