题目链接:点击打开链接
题意:给两个长为n的串,串中的元素由1-m种字符组成,若为0则未知并可为任意一个。现在要计算串1比串2字典序大的可能性模(1e9+7)的值。
思路:题目分为两部分内容,一个是计算概率,一个是计算分数模n的值。
计算概率:扫描字符串,分类讨论即可。讨论内容见代码。
计算模n的值:要计算P/Q %MOD,即计算P*Q^-1 %MOD = (P%MOD * Q^-1%MOD)%MOD。已知PQ互素且MOD为1e9+7,故可以采用乘法逆元计算Q^-1 %MOD,而该值也正是Q的乘法逆元。但是因为计算过程中需要多次平方,这里我还使用了模n快速幂进行计算。
AC代码如下:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
#define FSIO ios::sync_with_stdio(0);cin.tie(0);
#define DEBUG(a) cout<<"DEBUG: "<<(a)<<endl;
const int MOD = (int)1e9 + 7;
const int N = 200000 + 5;
int inv[N];
int init()
{
inv[1] = 1;
for(int i = 2; i < N; i ++)
inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
}
void ex_gcd(long long a, long long b, long long &x, long long &y, long long &d){
if (!b) {d = a, x = 1, y = 0;}
else{
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
long long cainv(long long t, long long p){
long long d, x, y;
ex_gcd(t, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
long long cal(long long num)
{
if(num<=N) return inv[num];
else return cainv(num,MOD);
}
long long powermod(long long n,long long k)
{
long long ans=1;
while(k)
{
if(k&1)
{
ans=((ans%MOD)*(n%MOD))%MOD;
}
n=((n%MOD)*(n%MOD))%MOD;
k>>=1;
}
return ans;
}
int s1[100005], s2[100005];
long long n, m;
long long ans;
int cnt;
int main()
{
FSIO;
init();
while(cin>>n>>m)
{
ans = 0;
cnt = 0;
for(int i=1;i<=n;++i) cin>>s1[i];
for(int i=1;i<=n;++i) cin>>s2[i];
for(int i=1;i<=n;++i)
{
if(s1[i]==0&&s2[i]==0)
{
long long temp = powermod(cal(m),cnt+1)*cal(2)%MOD;
ans = (ans + (temp*(m-1)))%MOD;
cnt++;
}
else if(s1[i]==0&&s2[i]!=0)
{
cnt++;
long long temp = powermod(cal(m),cnt);
ans = (ans+(temp*(m-s2[i])))%MOD;
}
else if(s1[i]!=0&&s2[i]==0)
{
cnt++;
long long temp = powermod(cal(m),cnt);
ans = (ans+(temp*(s1[i]-1)))%MOD;
}
else if(s1[i]>s2[i]) {ans =(ans+powermod(cal(m),cnt))%MOD;break;}
else if(s1[i]<s2[i]) break;
}
cout<<ans<<endl;
}
return 0;
}