CF935D Fafa and Ancient Alphabet 题解

讲一个很暴力的方法(为描述方便,下文 \(a\) 数组代表 \(s1\)\(b\) 数组代表 \(s2\))。

发现假如当前 \(a_i\ne b_i\),就不需要再向下枚举了,于是拥有了分类讨论的雏形。

我们设 \(inv\) 代表进行到这一步的概率,可分为以下四种情况:

  1. \(a_i>0,b_i>0\)。此时假如 \(a_i=b_i\),略过;若 \(a_i>b_i\)\(ans+=inv\),退出循环;否则直接退出循环。
  2. \(a_i>0,b_i=0\)。此时只需考虑确定的可增加概率和 \(inv\)。易得 \(inv=\frac{inv}{m},ans+=(a_i-1)inv\)
  3. \(a_i=0,b_i>0\)\(inv=\frac{inv}{m},ans+=(m-b_i)inv\)
  4. \(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;
}
posted @ 2024-03-07 22:06  长安一片月_22  阅读(2)  评论(0编辑  收藏  举报