• CF1151F


    1151F - Sonya and Informatics

    题意:有个长为n的01序列,求经过K次随机交换两个数之后这个序列非降的概率。n <= 100, k <= 1e9。

    解:看到这个数据范围想到了矩阵快速幂...

    先想一个暴力维护每个位置为1概率的DP,发现不独立...

    然后想到PKUSC T2,单独确定每一位,但是这个东西不是排列,有相同的元素不好搞...

    最后想到了thuPC摆家具,发现可以用那个套路。

    发现最终每个状态的概率只跟距初态的距离有关。这里的距离是两个状态异或之后1的个数。

    于是进行DP,设fij表示前i次操作,所得状态与初态异或后有j个1的概率。

    转移有三种,分别是无用转移,挪一个1到初态的0中,挪一个1到初态的1中。

    然后矩阵快速幂一下。

    最后算答案的时候,我们还要算出有多少种状态满足条件,这就是一个组合数。然后除以这个组合数就行了。

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 210, MO = 1e9 + 7;
      4 
      5 int n, K, A[N], fac[N], inv[N], invn[N], a[N][N], ans[N][N], c[N][N], lm;
      6 
      7 inline void Add(int &a, const int &b) {
      8     a += b;
      9     if(a >= MO) a -= MO;
     10     else if(a < 0) a += MO;
     11     return;
     12 }
     13 
     14 inline int qpow(int a, int b) {
     15     int ans = 1;
     16     while(b) {
     17         if(b & 1) {
     18             ans = 1ll * ans * a % MO;
     19         }
     20         a = 1ll * a * a % MO;
     21         b = b >> 1;
     22     }
     23     return ans;
     24 }
     25 
     26 inline int Inv(int x) {
     27     return qpow(x, MO - 2);
     28 }
     29 
     30 inline int iC(int n, int m) {
     31     if(n < 0 || m < 0 || n < m) return 0;
     32     return 1ll * invn[n] * fac[m] % MO * fac[n - m] % MO;
     33 }
     34 
     35 inline void mulself() {
     36     memset(c, 0, sizeof(c));
     37     for(int k = 0; k <= lm; k++) {
     38         for(int i = 0; i <= lm; i++) {
     39             if(!a[i][k]) continue;
     40             for(int j = 0; j <= lm; j++) {
     41                 Add(c[i][j], 1ll * a[i][k] * a[k][j] % MO);
     42             }
     43         }
     44     }
     45     memcpy(a, c, sizeof(a));
     46     return;
     47 }
     48 
     49 inline void mul() {
     50     memset(c, 0, sizeof(c));
     51     for(int k = 0; k <= lm; k++) {
     52         for(int i = 0; i <= lm; i++) {
     53             if(!a[i][k]) continue;
     54             for(int j = 0; j <= lm; j++) {
     55                 Add(c[i][j], 1ll * a[i][k] * ans[k][j] % MO);
     56             }
     57         }
     58     }
     59     memcpy(ans, c, sizeof(c));
     60     return;
     61 }
     62 
     63 int main() {
     64     scanf("%d%d", &n, &K);
     65     int cnt = 0, aim = 0;
     66     for(int i = 1; i <= n; i++) {
     67         scanf("%d", &A[i]);
     68         cnt += A[i];
     69     }
     70     for(int i = 1; i + cnt <= n; i++) {
     71         aim += A[i];
     72     }
     73     //int P = 1ll * Inv(n * (n - 1) / 2) * cnt % MO * (n - cnt) % MO;
     74     int P = Inv(n * (n - 1) / 2);
     75     fac[0] = inv[0] = invn[0] = 1;
     76     fac[1] = inv[1] = invn[1] = 1;
     77     for(int i = 2; i <= n; i++) {
     78         fac[i] = 1ll * i * fac[i - 1] % MO;
     79         inv[i] = 1ll * inv[MO % i] * (MO - MO / i) % MO;
     80         invn[i] = 1ll * invn[i - 1] * inv[i] % MO;
     81     }
     82     
     83     lm = n - cnt;
     84     for(int j = 0; j <= n - cnt; j++) {
     85         int t1 = 1ll * (cnt - j) * (n - cnt - j) % MO * P % MO;
     86         int t2 = 1ll * j * j * P % MO;
     87         Add(a[j][j], (1 - t1 + MO - t2 + MO) % MO);
     88         Add(a[j][j + 1], t1);
     89         Add(a[j][j - 1], t2);
     90     }
     91     for(int i = 0; i <= lm; i++) {
     92         ans[i][i] = 1;
     93     }
     94     
     95     while(K) {
     96         if(K & 1) {
     97             mul();
     98         }
     99         mulself();
    100         K >>= 1;
    101     }
    102     
    103     
    104     /*f[0][0] = 1;
    105     for(int i = 0; i < K; i++) {
    106         for(int j = 0; j <= n - cnt; j++) {
    107             //Add(f[i + 1][j], (1ll - P + MO) * f[i][j] % MO);
    108             int t1 = 1ll * (cnt - j) * (n - cnt - j) % MO * P % MO;
    109             int t2 = 1ll * j * j * P % MO;
    110             Add(f[i + 1][j + 1], 1ll * f[i][j] * t1 % MO);
    111             Add(f[i + 1][j - 1], 1ll * f[i][j] * t2 % MO);
    112             Add(f[i + 1][j], 1ll * f[i][j] * ((1 - t1 + MO - t2 + MO) % MO) % MO);
    113         }
    114     }*/
    115     
    116     int Ans = 1ll * ans[0][aim] * iC(n - cnt, aim) % MO * iC(cnt, aim) % MO;
    117     printf("%d
    ", (Ans + MO) % MO);
    118     return 0;
    119 }
    AC代码

    我的理解方式是,有两个集合S1,S2。S1里面是初态中为1的位置,S2是初态中为0的位置。我们要往S2里面放若干个1。每次可以不改变S2中1的个数,或者从S1拿一个1过来,或者从S2拿一个1出去。

    代码写的时候没注意j = 0的边界,可能会数组越界,但是A了...

  • 相关阅读:
    JVM基础系列第1讲:Java 语言的前世今生
    JVM基础系列开篇:为什么要学虚拟机?
    2018 精选文章集合
    如何唯一确定一个 Java 类?
    Java 中的 try catch 影响性能吗?
    不读大学也能成功,七个读大学的备用选择
    【中间件安全】IIS7.0 安全加固规范
    【中间件安全】Apache 安全加固规范
    Excel 保护工作表
    【应用安全】S-SDLC安全开发生命周期
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10962506.html
Copyright © 2020-2023  润新知