• [六省联考2017]分手是祝愿 期望DP


    表示每次看见期望的题就很懵逼。。。

    但是这题感觉还是值得一做,有可借鉴之处

    要是下面这段文字格式不一样的话(虽然好像的确不一样,我也不知道为什么,是直接从代码里面复制出来的,因为我一般都是习惯在代码里面敲注释。。。

    还是比较妙的。

    首先有一个贪心的最优策略,由于每盏灯最多开一次(两次就相当于没开),并且都只能影响它以及它之前的,

    也就是只能被后面的影响,所以从后往前遍历,如果一盏灯还是开的话,那我们就必须关掉它,

    不然就没人能关掉它了,于是这样我们可以得到对于初始状态的最优操作次数,

    这个时候,由于操作先后顺序不对答案造成影响,因此我们可以直接用这个最优操作次数来描述一个状态,

    而一开始的局面求出的最优操作次数t就是我们当前的状态,

    设f[i]为状态为i时的期望,因此我们要求的就是f[t],

    由于每盏灯都相当于是相互独立的,因此我们有:

    $f[i]=(i/n) * f[i-1] + (n-i)/n * f[i+1] + 1;$

    解释:
      当最优操作为i次时,我们有i/n的概率操作到这i盏灯中的一盏,这时状态变为f[i-1],

      而剩下的(n-i)/n的概率就会操作到其他的灯,于是这会让状态变坏,变为f[i+1],

      最后还要加上当前操作(正是这次操作导致了那些概率的产生)

      但是我们发现,这样的话,f[i]就需要用f[i-1]和f[i+1]来推了,显然不太好,
      于是考虑对式子进行化简:
    方法一:(我的推倒)
       令$g[i]=f[i] - f[i-1]$;

      于是直接对原式进行化简,如出现形如f[i] - f[i-1]之类的式子则用g[i]代替

      于是原式=$n * f[i] = i * f[i] + (n - i) * f[i+1] + n$

      ---> $n * f[i] - i * f[i-1] = (n - i) * f[i+1] + n$

      ---> $(n - i) * f[i] + i * f[i] - i * f[i-1] = (n - i) * f[i+1] + n$

    -   --> $(n - i) * f[i] + i * (f[i] - f[i-1]) = (n - i) * f[i+1] + n$

      ---> $(n - i) * f[i] + i * g[i] = (n - i) * f[i+1] + n$

      ---> $i * g[i] = (n - i) * f[i+1] - (n - i) * f[i] + n$

      ---> $i * g[i] = (n - i) * g[i+1] + n$

      ---> $g[i]=  frac{(n - i) * g[i+1] + n} {i}$

    方法二:(某大佬的推倒)

      令$f[i]=sum_{j = 1}^{i}{g[j]}$

      于是原式:

      $sum_{j = 1}^{i}{g[j]} = frac{i}{n} * sum_{j = 1}^{i - 1}{g[j]} +frac{n - i}{n} * sum_{j = 1}^{i + 1}{g[j]} + 1$

      ---> 因为$sum_{j = 1}^{i - 1}{g[j]}$ 与$ sum_{j = 1}^{i + 1}{g[j]}$的前i-1项相同,且系数相加刚好为1,

      于是将其提出,得到:$sum_{j = 1}^{i}{g[j]} = sum_{j = 1}^{i - 1}{g[j]} + frac{n - 1}{n} * (g[i] + g[i + 1]) + 1$

      $g[i] = frac{n - i}{n} * (g[i] + g[i + 1]) + 1$ 

      然后将g[i]移项并化简得到

      $g[i] = frac{(n - i) * g[i - 1] + n}{i}$

     
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define R register int
     4 #define AC 100100
     5 #define mod 100003
     6 #define LL long long
     7 int n,k;
     8 LL ans,t;
     9 LL g[AC],inv[AC];
    10 vector<int> limit[AC];
    11 bool z[AC];
    12 //bitset<AC> z;
    13 
    14 inline int read()
    15 {
    16     int x=0;char c=getchar();
    17     while(c > '9' || c < '0') c=getchar();
    18     while(c >= '0' && c <= '9') x=x*10+c-'0',c=getchar();
    19     return x;
    20 }
    21 
    22 void pre()
    23 {
    24     n=read(),k=read();
    25     for(R i=1;i<=n;i++) z[i]=read();
    26     inv[1]=1;
    27     for(R i=2;i<=n;i++) inv[i]=((mod - mod / i) * inv[mod % i]) % mod;
    28 }
    29 
    30 void count()//计算出要求的状态是什么
    31 {
    32     for(int i=1;i<=n;i++)
    33         for(R j=i;j<=n;j+=i)//很妙的枚举约数方法,其思想是枚举每一个约数对哪些数造成了贡献(成为它的约数)
    34             limit[j].push_back(i);
    35     for(R i=n;i>=1;i--)
    36         if(z[i])
    37         {
    38             for(R j=0;j<limit[i].size();j++) z[limit[i][j]]^=1;
    39             t++;
    40         }    
    41 //    printf("%d
    ",t);
    42 }
    43 //当状态为f[n]时,无论怎么操作都是对的,于是一定会指向f[n-1],
    44 //所以g[n]=1,大概意思是从f[n]的状态推出题目所给的f[t]的状态的答案
    45 
    46 void work()
    47 {
    48     if(t <= k) ans=t;
    49     else
    50     {
    51         g[n]=1;
    52         int be=n-1;
    53         for(R i=be;i > k;i--) g[i]=( ((LL)(n - i) * g[i + 1] + n) * inv[i]) % mod; 
    54         for(R i=t;i>k;i--) ans=(ans + g[i]) % mod;//统计当前状态到k之间的期望
    55         ans=(ans + k) % mod;//最后就直接加k了
    56     } 
    57     for(R i=1;i<=n;i++) ans=(ans * i) % mod;
    58     printf("%lld
    ",ans);
    59 }
    60 
    61 int main()
    62 {
    63     freopen("in.in","r",stdin);
    64     pre();
    65     count();
    66     work();
    67     fclose(stdin);
    68     return 0;
    69 }
     
  • 相关阅读:
    golang image库的使用
    http1.0/1.1/2.0/h2c/golang使用随笔
    3、逻辑回归 && 正则化
    1、Batch Normalization
    5、极大似然估计
    4、交叉熵与softmax
    2、卷积核,感受野
    Vue学习
    Qeios、github、overleaf、paperwithcode, 越来越多的web云端工具
    投稿遇到的arxiv论文引用问题的办法
  • 原文地址:https://www.cnblogs.com/ww3113306/p/8867536.html
Copyright © 2020-2023  润新知