添加链接描述
1 首先来思考 对于一个 排列和 字符串,我们怎样判断他是否可行。
可以把 p 数组的 n 个数之间的 n - 1 个空挡看作 n - 1 个通道, 这个通道有两种状态, 一种是开启, 一种是关闭, 如果开启, 意味着可以交换左右两个数(只有这个通道 前面是 是 “L”,后面的是“R”,这种情况下,才是关闭的)
对于【1-i 】的前缀,正常情况下 最大值因该是 i ,如果最大值>i 说明有元素要向后移动。所以我们的第i 个通道要开启(不会出现最大值< i 的情况)
2 我们可以维护需要开启但实际是关闭的通道的数量。
每次修改,我最多影响两个通道。我们直接维护 变化的情况。维护cnt ,当我的cnt 为0,说明是可以的。
void solve()
{
int n, q;
cin >> n >> q;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i];
string s;
cin >> s;
s = " " + s;
vector<int> need(n); // 这个通道是否需要是开启的
int mx = 0;
for (int i = 1; i < n; i++)
{
mx = max(a[i], mx);
if (mx > i)
need[i] = 1;
}
vector<int> ok(n,1);
for (int i=1;i<n;i++)
{
if (s[i]=='L'&&s[i+1]=='R')
ok[i]=0;
}
int cnt=0; // 有多少通道的状态是不对的
for (int i=1;i<n;i++)
{
if (ok[i]==0&&need[i]==1)
cnt++;
}
// cout<<cnt<<"\n";
while (q--)
{
int pos;
cin >> pos;
if (s[pos]=='L')
s[pos]='R';
else s[pos]='L';
if (pos-1>=1)
{
if (s[pos-1]=='L'&&s[pos]=='R')
{ // 原来一定可以
ok[pos-1]=0;
if (need[pos-1]==1)
cnt++;
}
else
{
if (ok[pos-1]==0&&need[pos-1]==1)
cnt--;
ok[pos-1]=1;
}
}
if (pos+1<=n)
{
if (s[pos]=='L'&&s[pos+1]=='R')
{ ok[pos]=0;
if (need[pos]==1)
cnt++;
}
else
{
if (ok[pos]==0&&need[pos]==1)
cnt--;
ok[pos]=1;
}
}
if (cnt==0)
cout<<"YES\n";
else cout<<"NO\n";
}
}
i
div3 984
这个题 也是一样的套路。因为每次修改只会 影响 四个位置。所以我们每次修改的时候,遍历这四个位置的情况就可以了。