CF Div3 962補題 E-F
E. Decode
連結:
Problem - E - Codeforces
簡要題意:
給你一個長度為 \(n\) 的二進位制字串\(s\) 。對於每一對整數\((l, r)\) \((1 \leq l \leq r \leq n)\) 中,數出 \((x, y)\) \((l \leq x \leq y \leq r)\) 這樣的整數對的個數。 \((l \leq x \leq y \leq r)\) 中的 \(\mathtt{0}\) 的數量等於子串 \(s_xs_{x+1}...s_y\).中的 \(\mathtt{1}\) 的數量。
輸出所有可能的 \((l, r)\) modulo \(10^9+7\) 的計數之和。
思路:
- 很明顯這樣的題目算區間貢獻和字首和有關
- 我們定義子串左邊位置為x 子串右邊位置設為y
- 我們發現一個01數量相同的子串 對於整個陣列的貢獻是 \(x * (n-y+1)\)
- 算01相同數量我們可以用字首和 + map實現
- 每次將x + 1的貢獻累加到map中
- 計算答案 ans = mp[pre[i]] * (n-i+1)
程式碼:
void solve(){
string s;
cin >> s;
int n = s.size();
s = " " +s;
map<int,int> h;
int pre = 0;
int ans = 0;
h[0] = 1;
for(int i = 1;i<=n;i++){
if(s[i]=='0') pre--;
else pre++;
ans+=h[pre]*(n-i+1)%P;
ans%=P;
h[pre]+=i+1;
h[pre]%P;
}
cout << ans <<endl;
}
F. Bomb
連結:
Problem - F - Codeforces
簡要題意:
- 給你兩個陣列 \(a[n]\) 和 $ b[n]$ \((1<= n <= 2e5)\)
- 你可以執行最多k次下列操作 \((1<= k <= 1e9)\)
- 選擇 \(a[i]\) 將 \(a[i]\) 加入到你的分數中 然後使\(a[i] = max(0,a[i] - b[i])\)
- 求最大分數
思路:
- 首先一個O(k)的思路是 將所有a[i]放入優先佇列中,然後不斷取k個最大的優先佇列top即可,每次取出來都更新優先佇列的值 \(a[i] = max(0,a[i] - b[i])\) 再放入,因為可以取多次
- k有1e9,顯然該思路不行
- 這麼大的資料量 很自然的指向了二分,我們要二分什麼?
- 二分一個x,此x為我每次取數字,至少要取大於等於x的數 (核心)
- 我們得到取大於等於x的數會有一個操作次數,我們要使操作次數f(x) <= k, 並且取max(f(x));
- 然後我們就會得到一個x,我們把每個數取的的貢獻不斷加入答案中,這步可用等差數列求和
- 我們還有一部分是 (k - f(x)) 即剩餘操作次數,我們發現 如果x更小,那麼操作次數f(x) 會 > k,那麼我們只要取(k - f(x))個 x加入答案即可完成最後一部分的補充(這步很難理解,筆者建議多思考一下為什麼這樣補充)
程式碼:
const int N = 200005;
int a[N],b[N],n,k;
bool check(int mid){
int y = 0;
for(int i = 1;i<= n;i++){
if(a[i]>=mid){
y += (a[i] - mid + b[i] - 1)/b[i];
}
}
return y <= k;
}
void solve(){
cin >> n >> k;
for(int i = 1;i<=n;i++){
cin >>a[i];
}
for(int i = 1;i<=n;i++){
cin >>b[i];
}
int l=0,r=1e12,x=-1;
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid)){
r = mid - 1;
x = mid;
}else{
l = mid + 1;
}
}
int us = 0;
int ans = 0;
for(int i = 1;i<=n;i++){
if(a[i] >= x){
int t = (a[i] - x + b[i] - 1)/b[i];
//(a[i] + a[i] - b[i]*(t - 1))*t/2;
ans += (a[i] + a[i] - b[i]*(t - 1))*t/2;
us+=t;
}
}
ans += (k - us)*x;
cout << ans << endl;
}
signed main(){
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int times = 1;
cin >> times;
while(times--){
solve();
}
return 0;
}