
∗∗**∗∗ 出题人出的模数是 998244853998244853998244853,调了一个小时说怎么 dfsdfsdfs 都要错,回过头了看题才发现
果然细节决定成败
转换一下题意,就是选一个全排列,然后到一个点就把 pip_ipi 的这个位置改成 000
遇到的第一个 1 的位置就是答案
考虑直接枚举最后的不合法的弦的出现位置 iii
那么显然 iii 前面的任意一个为 1 的位置 jjj,那么 jjj 在排列中出现在 jjj 之前
第一个的概率是 j−1n\frac{j-1}{n}nj−1,第二个是 j′−1n−1\frac{j'-1}{n-1}n−1j′−1…
然后还要保证当前的数 iii 在排列中的出现位置在 iii 之后
显然概率为 n−in−cnt\frac{n-i}{n-cnt}n−cntn−i
#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
cs int N = 1e6 + 5;
int n; char s[N];
cs int Mod = 998244853;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int ksm(int a, int b){ int ans = 1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans = mul(ans, a); return ans; }
int inv[N];
int main(){
n = read();
scanf("%s", s + 1);
if(s[1] - '0' == 1){ puts("1"); return 0; }
inv[0] = inv[1] = 1;
for(int i = 2; i <= n; i++) inv[i] = mul(Mod-Mod/i, inv[Mod%i]);
int nx = n, ct = 0, p = 1;
int ans = 0;
for(int i = 1; i <= n; i++){
if(s[i] - '0' == 0) continue;
// 遇到一个 1 先算以它为答案的概率
int ret = mul(p, mul(inv[nx], n - i + 1));
ans = add(ans, mul(i, ret));
// 更新不选它的概率
p = mul(p, mul(inv[nx], i - ct - 1));
nx--; ct++;
}
// 还要算为 n 的概率
ans = add(ans, mul(n, p));
cout << ans; return 0;
}
本文探讨了一道涉及模数998244853的编程题,通过概率论的方法解决全排列中特定模式的出现概率问题,详细解析了算法思路与实现代码。
1万+

被折叠的 条评论
为什么被折叠?



