BZOJ4872: [Shoi2017]分手是祝願【機率指望DP】【思惟好題】

Description

Zeit und Raum trennen dich und mich.c++

時空將你我分開。B 君在玩一個遊戲,這個遊戲由 n 個燈和 n 個開關組成,給定這 n 個燈的初始狀態,下標爲從 1 到 n 的正整數。每一個燈有兩個狀態亮和滅,咱們用 1 來表示這個燈是亮的,用 0 表示這個燈是滅的,遊戲的目標是使全部燈都滅掉。可是當操做第 i 個開關時,全部編號爲 i 的約數(包括 1 和 i)的燈的狀態都會被改變,即從亮變成滅,或者是從滅變成亮。B 君發現這個遊戲很難,因而想到了這樣的一個策略,每次等機率隨機操做一個開關,直到全部燈都滅掉。這個策略須要的操做次數不少, B 君想到這樣的一個優化。若是當前局面,能夠經過操做小於等於 k 個開關使全部燈都滅掉,那麼他將再也不隨機,直接選擇操做次數最小的操做方法(這個策略顯然小於等於 k 步)操做這些開關。B 君想知道按照這個策略(也就是先隨機操做,最後小於等於 k 步,使用操做次數最小的操做方法)的操做次數的指望。這個指望可能很大,可是 B 君發現這個指望乘以 n 的階乘必定是整數,因此他只須要知道這個整數對 100003 取模以後的結果。算法

Input

第一行兩個整數 n, k。優化

接下來一行 n 個整數,每一個整數是 0 或者 1,其中第 i 個整數表示第 i 個燈的初始狀況。spa

1 ≤ n ≤ 100000, 0 ≤ k ≤ n;code

Output

輸出一行,爲操做次數的指望乘以 n 的階乘對 100003 取模以後的結果。遊戲

Sample Input

4 0
0 0 1 1ip

Sample Output

512input


思路

假設沒有隨機it

咱們考慮當前的最優算法,確定是從後往前來看有哪些須要被更新的io

那麼這樣就很容易算出最開始咱們最少須要走幾步

而後是\(dp_{i}\)表示從最少i步走到最少i-1步的指望步數

咱們考慮由於當前有i步都是須要走的,因此當前這一步轉移到i-1的機率是\(\frac{i}{n}\)

而後就是走到i+1,機率\(1-\frac{i}{n}\),指望步數能夠從\(dp_{i+1}\)轉移

總的轉移是\(dp_{i}=\frac{i}{n}+(1-\frac{i}{n})*(1+dp_{i}+dp_{i+1})\)

移項消元獲得\(dp_{i}=\frac{n+(n-i)*dp_{i+1}}{i}\)

而後就作完了,前綴和累加就好了


#include<bits/stdc++.h>

using namespace std;

const int Mod = 1e5 + 3;
const int N = 1e5 + 10;

int n, k, a[N], f[N], fac = 1;

int add(int a, int b) {
  return (a += b) >= Mod ? a - Mod : a;
}

int sub(int a, int b) {
  return (a -= b) < 0 ? a + Mod : a;
}

int mul(int a, int b) {
  return 1ll * a * b % Mod;
}

int fast_pow(int a, int b) {
  int res = 1;
  for (; b; b >>= 1, a = mul(a, a)) {
    if (b & 1) res = mul(res, a);
  }
  return res;
}

int main() {
  scanf("%d %d", &n, &k);
  for (int i = 1; i <= n; i++) {
    scanf("%d", &a[i]);
    fac = mul(fac, i);
  }
  int num = 0;
  for (int i = n; i >= 1; i--) {
    for (int j = i << 1; j <= n; j += i) {
      a[i] ^= a[j];
    }
    if (a[i]) ++num;
  }
  for (int i = 1; i <= k; i++) f[i] = 1;
  for (int i = n; i > k; i--) {
    f[i] = mul(add(n, mul(n - i, f[i + 1])), fast_pow(i, Mod - 2));
  }
  int ans = 0;
  for (int i = 1; i <= num; i++) {
    ans = add(ans, f[i]);
  }
  printf("%d", mul(ans, fac));
  return 0;
}
相關文章
相關標籤/搜索