• #775 Div.1 C. Tyler and Strings 组合数学


    C
    组合数学,1900,数状数组

    题意

    给出 s , t s, t s,t 两个序列,长度分别为 n , m n,m n,m,问 s s s 有多少种排序方式满足 s s s 的字典序比 t t t 小。 1 ≤ n , m ≤ 2 e 5 1\leq n,m\leq 2e5 1n,m2e5

    思路

    因为是按字典序比较,所以如果 s 1 < t 1 s_1<t_1 s1<t1 之后的就可以随便排了,所以考虑枚举前 i − 1 i-1 i1 位相同且 s i < t i s_i<t_i si<ti 的排序方式有 c n t i cnt_i cnti 种,最后的答案就是 ∑ i = 1 i = n c n t i \sum_{i=1}^{i=n} cnt_i i=1i=ncnti

    那么如何求 c n t i cnt_i cnti 呢?如果不考虑可重复排列,那么 c n t i = n o w × ( n − i ) ! cnt_i= now \times (n-i)! cnti=now×(ni)! ,即到第 i 位当前满足小于 t i t_i ti 的个数乘上之后数的全排列(因为 i i i 后面的数可以随便取了)。 n o w now now 可以直接用数状数组维护前缀和(因为前 i − 1 i-1 i1 位两序列相同,所以可以直接将那个数字数量减1)。于是问题重点在于加上可重复排列后怎么做。

    首先可重复排列要在 n ! n! n! 的基础上除以每个元素出现数量的阶乘。即当我们遍历到第 i i i 位时,要在 ( n − i ) ! (n-i)! (ni)! 的基础上除以 c n t 1 ! × c n t 2 ! × c n t i ! . . . . × c n t n ! {cnt_1!\times cnt_2!\times cnt_i!....\times cnt_n!} cnt1!×cnt2!×cnti!....×cntn!
    其中 c n t 1 cnt_1 cnt1减去前 i − 1 i-1 i1 位数字后的对应数字的数量。然后我们就可以先预处理出 i = 0 i=0 i=0 时的上式记为 fenzi,由
    1 c n t 1 ! × c n t 2 ! × ( c n t i − 1 ) ! . . . . × c n t n ! = 1 c n t 1 ! × c n t 2 ! × c n t i ! . . . . × c n t n ! × c n t i \frac{1}{cnt_1!\times cnt_2!\times (cnt_i-1)!....\times cnt_n!}=\frac{1}{cnt_1!\times cnt_2!\times cnt_i!....\times cnt_n!}\times cnt_i cnt1!×cnt2!×(cnti1)!....×cntn!1=cnt1!×cnt2!×cnti!....×cntn!1×cnti,只需每次遍历后将 fenzi *= cnt[t[i]] 并更新 cnt[t[i]] 即可。

    ps.不要忘记考虑 s s s 可能恰好为 t t t 的前缀的情况,开始忘了,还好有样例1

    代码

    void solve() {
       cin >> n >> m;
       fac[0] = 1;
       for(int i = 1; i <= n; i++) {
       	fac[i] = (fac[i-1] * i) % P;
       }
       for(int i = 1; i <= n; i++) {
       	cin >> s[i];
       	update(s[i], 1);
       	cnt[s[i]]++;
       }
       for(int i = 1; i <= m; i++) {
       	cin >> t[i];
       }
       int ans = 0;
       int mi = min(n, m);
       int fz = 1;
       for(int i = 1; i <= 2e5; i++) {
       	if(cnt[i]) {
       		fz = fz * fac[cnt[i]] % P;
       	}
       }
       fz = power(fz, P - 2);
       int flag = 1;
       if(n >= m) {
       	flag = 0;
       }
       for(int i = 1; i <= mi; i++) {
       	int p = ask(t[i] - 1);
       	ans = (ans + p * fac[n-i] % P * fz % P) % P;
       	if(!cnt[t[i]]) {
       		flag = 0;
       		break;
       	}
       	fz = fz * cnt[t[i]] % P;
       	cnt[t[i]]--;
       	update(t[i], -1);
       }
       ans += flag;
       ans %= P;
       cout << ans << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
  • 相关阅读:
    俩表关联更新
    物联网安全的概念
    MIPI CSI-2笔记(10) -- Low Level Protocol(延迟降低、传输效率增强特性LRTE)
    puzzle(018.4)珍珑棋局
    土壤水势传感器陶质材料不存在因降解引起的漂移
    【Educoder作业】问题求解——网页数据获取
    沃通SSL证书服务多省区一体化政务服务平台
    手把手教你Linux磁盘分区与文件挂载
    【iOS】—— weak的基本原理
    【AI实用技巧】GPT写sql统计语句
  • 原文地址:https://blog.csdn.net/m0_59273843/article/details/125512674