讲一个很暴力的方法(为描述方便,下文 \(a\) 数组代表 \(s1\),\(b\) 数组代表 \(s2\))。
发现假如当前 \(a_i\ne b_i\),就不需要再向下枚举了,于是拥有了分类讨论的雏形。
我们设 \(inv\) 代表进行到这一步的概率,可分为以下四种情况:
- \(a_i>0,b_i>0\)。此时假如 \(a_i=b_i\),略过;若 \(a_i>b_i\),\(ans+=inv\),退出循环;否则直接退出循环。
- \(a_i>0,b_i=0\)。此时只需考虑确定的可增加概率和 \(inv\)。易得 \(inv=\frac{inv}{m},ans+=(a_i-1)inv\)。
- \(a_i=0,b_i>0\)。\(inv=\frac{inv}{m},ans+=(m-b_i)inv\)。
- \(a_i=0,b_i=0\)。\(ans+=\frac{m(m-1)}{2m^2}inv,inv=\frac{inv}{m}\)。
都是在 \(\mod p\) 意义下的。时间复杂度 \(O(n\log_2n)\),预处理一些快速幂可优化至 \(O(n)\)。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll p=1e9+7;
const int N=1e5+5;
ll qpow(ll x,int y){
ll re=1;
while(y){
if(y&1) re=re*x%p;
x=x*x%p;
y>>=1;
}return re;
}int n,a[N],b[N];
ll ans,inv=1,m;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
cin>>b[i];
for(int i=1;i<=n;i++){
if(a[i]&&b[i]){
if(a[i]==b[i])
continue;
if(a[i]>b[i])
ans=(ans+inv)%p;
break;
}if(!a[i]&&!b[i]){
ans=(ans+m*(m-1)%p*qpow(m*m*2%p,p-2)%p*inv%p)%p;
inv=inv*qpow(m,p-2)%p;
}else if(!a[i]){
inv=inv*qpow(m,p-2)%p;
ans=(ans+(m-b[i])*inv%p)%p;
}else{
inv=inv*qpow(m,p-2)%p;
ans=(ans+(a[i]-1)*inv%p)%p;
}
}cout<<ans;
return 0;
}
标签:qpow,Alphabet,int,题解,inv,re,ans,Fafa,ll
From: https://www.cnblogs.com/chang-an-22-lyh/p/18059903/cf935d-tj