远古人的历史(history)
题意:
给定一个由 * 和 | 组成的字符串,其中 * 必须在 | 前面。
数值是 *的数量 × 5 加上 |的数量 × 1。
每次修改将某个位置改成 ?,表示这个位置可以填 * 或 |,但要保证书写规范(即所有 * 在所有 | 前面)。
每次修改后都要输出所有可能的数字的数值和。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
string s;
int q;
int f[N];// 记录每个位置当前是什么:0表示?,1表示*,2表示|
int main(){
cin >> s >> q;
s=' '+s;
int len=s.size()-1;
int r=0,l=len+1;//r:最后一个'*',l:第一个'|'
for(int i=1;i<=len;i++){
if(s[i]=='*'){
f[i]=1;
r=i;
}else if(s[i]=='|'){
f[i]=2;
if(l==len+1) l=i;
}
}
while(q--){
int x;
cin >> x;
f[x]=0;
if(r==x){
while(r>0&&f[r]!=1) r--;
}
if(l==x){
while(l<=len&&f[l]!=2) l++;
}//维护区间
ll L=r,R=l-1;
if(L>R) cout << "0\n";
else{
ll ans=R-L+1;
ll sum=(L+R)*ans/2;
ll tot=4*sum+len*ans;
cout << tot << '\n';
}
}
return 0;
}
此代码思路为:
1.设:
R=最后一个 * 的位置
L=第一个 | 的位置
区间 [R+1, L-1] 中每个位置可以填或|,但要保持规范。
有效字符串的个数=L-R
维护L,R每次位数发生变化,都去更新
2.计算
对于每个位置k,有前k个'',后n-k个'|'
这一串数值为:
数值= 5(的个数)+1(|的个数)
=5k+n-k
=n+4k
后用等差数列求和
总和=(k=L 到 R) n+(k=L 到 R)4k
=n(R-L+1)+ 4(k=L 到 R)k
总和 =ncnt+4(L+R)cnt/2
=cntn+2(L+R)*cnt
就是
ll ans = R - L + 1; // cnt = 区间长度
ll sum = (L + R) * ans / 2; // 等差数列求和 (k=L 到 R) k
ll tot = 4 * sum + n * ans; // 4*sum + n*cnt
总复杂度为O(q+n)

浙公网安备 33010602011771号