CF1698E PermutationForces II Solution
UPD:修改了一个错误,感谢评论区指出(
搞出一个比官方题解更优的
题意
给定
题解
我们发现对一定范围内的数进行选择比较麻烦,因此我们考虑把交换数组中的两个数改为交换两个数的下标。我们可以将操作换成在下标数组上进行操作。
具体地说,首先我们构造一个数组
类似地我们构造一个数组
- 若数
i 在b 中的下标已经确定为j ,令d_i=j ; - 若数
i 在b 中的下标未确定(即被替换为-1 ),令d_i=-1 。
那么我们就可以将题目中的操作转化为:
第
这样我们每次都是操作的范围是连续的一段区间,显然舒服的多。
现在我们再来分析被转化后的操作。
我们可以发现下面几点:
-
- 第
i 步的操作对后续操作的可选下标对应数值的范围的影响仅仅为不能选择第i 步操作后的c_i ; - 若第
i 步选择的x,y 均不等于i ,那么这对序列后续操作的影响和x=y=i 时等价,因为此时的x,y 的选择对后续每个位置可选的数的范围没有影响。
因此我们不妨令第
进一步地,我们还可以将“操作”转化为:
第
最终,
这样,我们就会发现每一个未确定的
此外,我们判断是否存在解的方式就是看是否存在
判断是否有解之后,将
如果还有不懂的地方就看看代码吧~
代码
#include<cstdio>
#include<iostream>
#define MAXN 200000
#define MOD 998244353
using namespace std;
int a[MAXN+5],b[MAXN+5],c[MAXN+5],d[MAXN+5];
bool vis[MAXN+5];
int main() {
ios::sync_with_stdio(0);
int t,n,s,cnt,p;
bool flag;
long long ans;
cin>>t;
while (t--) {
ans=1;cnt=0;flag=0;p=0;
cin>>n>>s;
for (int i=1;i<=n;++i) d[i]=-1,vis[i]=0;
for (int i=1;i<=n;++i) cin>>a[i],c[a[i]]=i;
for (int i=1;i<=n;++i) cin>>b[i];
for (int i=1;i<=n;++i) if (b[i]!=-1) d[b[i]]=i,vis[i]=1;
for (int i=1;i<=n;++i) if (a[d[i]]-i>s) flag=1;
if (flag==1) {
cout<<"0\n";
continue;
}
for (int i=1;i<=n;++i) {
while (p<i+s&&p<n) {++p;if (!vis[c[p]]) ++cnt;}
if (d[i]==-1) {
ans=(ans*cnt)%MOD;
--cnt;
}
}
cout<<ans<<"\n";
}
return 0;
}