CGAK 都是好题,尤其喜欢 C
The 3rd Universal Cup. Stage 22: Zhengzhou - Dashboard - Contest - QOJ.ac https://codeforces.com/gym/543949/ https://codeforces.com/gym/105632 
题目分区:LBFM / C / GK / AJDIEH
给定三个正整数p A , p B , p C p_{A},p_{B},p_{C} p A  , p B  , p C  A , B , C A,B,C A , B , C p A , p B , p C p_{A},p_{B},p_{C} p A  , p B  , p C  A ⊕ B = C A\oplus B=C A ⊕ B = C 1 0 6 10^{6} 1 0 6 
拿到这题的第一反应是设p A = d p q ,   p B = d p r ,   p C = d q r p_{A} = dpq,\ p_{B} = dpr,\ p_{C} = dqr p A  = d p q ,   p B  = d p r ,   p C  = d q r p A = d p q a ,   p B = d p r b ,   p C = d q r c p_{A} = dpqa,\ p_{B} = dprb,\ p_{C} = dqrc p A  = d p q a ,   p B  = d p r b ,   p C  = d q r c 
事实上,有解的必要条件是
{ p C ∣ lcm  ( p A , p B ) p A ∣ lcm  ( p B , p C ) p B ∣ lcm  ( p C , p A )    ⟺    p A = d p q ,   p B = d p r ,   p C = d q r \begin{cases} p_{C} \mid \operatorname{lcm}(p_{A},p_{B}) \\ p_{A} \mid \operatorname{lcm}(p_{B},p_{C}) \\ p_{B} \mid \operatorname{lcm}(p_{C},p_{A}) \\ \end{cases} \iff p_{A} = dpq,\ p_{B} = dpr,\ p_{C} = dqr ⎩ ⎪ ⎪ ⎨ ⎪ ⎪ ⎧  p C  ∣ l c m ( p A  , p B  ) p A  ∣ l c m ( p B  , p C  ) p B  ∣ l c m ( p C  , p A  )  ⟺ p A  = d p q ,   p B  = d p r ,   p C  = d q r 
简要证明如下:考虑S = A ⊕ B S = A\oplus B S = A ⊕ B p S = lcm  ( p A , p B ) p_{S} = \operatorname{lcm}(p_{A},p_{B}) p S  = l c m ( p A  , p B  ) C = S C=S C = S p S p_{S} p S  p C p_{C} p C  p C ∣ p S p_{C} \mid p_{S} p C  ∣ p S  p C ∣ lcm  ( p A , p B ) p_{C} \mid \operatorname{lcm}(p_{A},p_{B}) p C  ∣ l c m ( p A  , p B  ) 
至于是否充分,我们只要能构造出来就是充分的。
首先判掉一些平凡的情形。
以下不妨设d = gcd  ( p A , p B , p C ) = 1 d = \gcd(p_{A},p_{B},p_{C}) = 1 d = g cd( p A  , p B  , p C  ) = 1 d − 1 d-1 d − 1 
如果存在恰好两个相等,不妨p A = p B p_{A}=p_{B} p A  = p B  d = gcd  ( p A , p B , p C ) = 1 d = \gcd(p_{A},p_{B},p_{C}) = 1 d = g cd( p A  , p B  , p C  ) = 1 p C = 1 p_{C}=1 p C  = 1 
剩下就是互不相同,设p A = p q ,   p B = p r ,   p C = q r p_{A} = pq,\ p_{B} = pr,\ p_{C} = qr p A  = p q ,   p B  = p r ,   p C  = q r p ≠ q ≠ r p \neq q \neq r p  = q  = r p , q , r p,q,r p , q , r 1 0 ′ 1 0 ′ 10 ⊕ 10 0 ′ 100 = 001110 10'10'10\oplus 100'100=001110 1 0 ′ 1 0 ′ 1 0 ⊕ 1 0 0 ′ 1 0 0 = 0 0 1 1 1 0 1 0 ′ 1 0 ′ 1 0 ′ 1 0 ′ 10 ⊕ 1000 0 ′ 10000 10'10'10'10'10\oplus 10000'10000 1 0 ′ 1 0 ′ 1 0 ′ 1 0 ′ 1 0 ⊕ 1 0 0 0 0 ′ 1 0 0 0 0 10 0 ′ 10 0 ′ 10 0 ′ 10 0 ′ 100 ⊕ 1000 0 ′ 1000 0 ′ 10000 100'100'100'100'100\oplus 10000'10000'10000 1 0 0 ′ 1 0 0 ′ 1 0 0 ′ 1 0 0 ′ 1 0 0 ⊕ 1 0 0 0 0 ′ 1 0 0 0 0 ′ 1 0 0 0 0 
QED.
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 #include  <bits/stdc++.h>  using  namespace  std;using  ll = long  long ;using  ull = unsigned  long  long ;using  ulll = unsigned  __int128;int  main ()      int  T;     cin >> T;     while  (T--) {         int  pA, pB, pC;         cin >> pA >> pB >> pC;         if  (lcm (pA, pB) % pC || lcm (pA, pC) % pB || lcm (pB, pC) % pA) {             cout << "NO"  << endl;         } else  if  (pA == pB && pB == pC) {             if  (pA == 2 ) {                 cout << "NO"  << endl;             } else  if  (pA == 1 ) {                 cout << "YES"  << endl;                 cout << 1  << endl;                 cout << 1  << endl;                 cout << 0  << endl;             } else  {                 cout << "YES"  << endl;                 cout << "10"  << string (pA - 2 , '0' ) << endl;                 cout << "01"  << string (pA - 2 , '0' ) << endl;                 cout << "11"  << string (pA - 2 , '0' ) << endl;             }         } else  {             int  d = gcd (gcd (pA, pB), pC);             string a, b, c;             pA /= d;             pB /= d;             pC /= d;             if  (pA == 1  || pB == 1  || pC == 1 ) {                 if  (pA == 1 ) {                     a = "1" ;                     b = "1"  + string (pB - 1 , '0' );                     c = "0"  + string (pC - 1 , '1' );                 } else  if  (pB == 1 ) {                     a = "0"  + string (pA - 1 , '1' );                     b = "1" ;                     c = "1"  + string (pC - 1 , '0' );                 } else  {                     a = "1"  + string (pA - 1 , '0' );                     b = "0"  + string (pB - 1 , '1' );                     c = "1" ;                 }             } else  {                 int  p = gcd (pA, pB);                 int  q = gcd (pA, pC);                 int  r = gcd (pB, pC);                 for  (int  i = 0 ; i < pA; i++) {                     int  x = (i % p == 0 ) ^ (i % q == 0 );                     a += x + '0' ;                 }                 for  (int  i = 0 ; i < pB; i++) {                     int  x = (i % p == 0 ) ^ (i % r == 0 );                     b += x + '0' ;                 }                 for  (int  i = 0 ; i < pC; i++) {                     int  x = (i % q == 0 ) ^ (i % r == 0 );                     c += x + '0' ;                 }             }             cout << "YES"  << endl;             for  (auto & x : a) cout << x << string (d - 1 , '0' ); cout << endl;             for  (auto & x : b) cout << x << string (d - 1 , '0' ); cout << endl;             for  (auto & x : c) cout << x << string (d - 1 , '0' ); cout << endl;         }     }       return  0 ; } 
折一个四面体,实际操作后发现,底面相同时,三个侧面的数字是确定的,因此每个位置只可能走过一次。BFS 即可。时间复杂度O ( n 2 ) \mathcal{O}(n^{2}) O ( n 2 ) 
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include  <bits/stdc++.h>  using  namespace  std;const  int  dx[2 ][3 ] = {    { 0 , 0 , -1  },     { 0 , 0 , 1  }, }; const  int  dy[2 ][3 ] = {    { -1 , 1 , -1  },     { -1 , 1 , 1  }, }; const  int  to[2 ][5 ][3 ] = {{     {},      { 2 , 4 , 3  },      { 1 , 3 , 4  },      { 4 , 2 , 1  },      { 3 , 1 , 2  } }, {      {},      { 4 , 2 , 3  },      { 3 , 1 , 4  },      { 2 , 4 , 1  },      { 1 , 3 , 2  } }}; int  main ()      ios::sync_with_stdio (false );     cin.tie (nullptr ); cout.tie (nullptr );     int  n;     cin >> n;     vector mp (n + 2 , vector<int >(2  * n + 3 ))  ;     for  (int  i = 1 ; i <= n; i++) {         for  (int  j = 1 ; j <= 2  * i - 1 ; j++) {             cin >> mp[i][j];         }     }     queue<pair<int , int >> Q;     Q.push ({ 1 , 1  });     vector dis (n + 2 , vector<int >(2  * n + 3 , -1 ))  ;     dis[1 ][1 ] = 0 ;     while  (!Q.empty ()) {         auto  [x, y] = Q.front ();          Q.pop ();         bool  op = y & 1 ;         for  (int  i = 0 ; i < 3 ; i++) {             int  nx = x + dx[op][i], ny = y + dy[op][i];             if  (mp[nx][ny] == 0 ) continue ;             if  (dis[nx][ny] != -1 ) continue ;             if  (mp[nx][ny] == to[op][mp[x][y]][i]) {                 dis[nx][ny] = dis[x][y] + 1 ;                 Q.push ({ nx, ny });             }         }     }     int  x, y;     cin >> x >> y;     cout << dis[x][y] << endl;     return  0 ; } 
正着不好做,但如果倒推,操作就是唯一的。
从目标倒着模拟,得到一组答案,顺便得到了有解条件以及策略的正确性。
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 #include  <bits/stdc++.h>  using  namespace  std;bool  check (int  x)      assert (x > 0 );     return  (x & (x - 1 )) == 0 ; } int  main ()      int  A, B, X, Y;     cin >> A >> B >> X >> Y;          A = max (1 , A);     B = max (1 , B);            int  d1 = gcd (A, X), d2 = gcd (B, Y);     if  (!check (A / d1) || !check (B / d2)) {         cout << -1  << endl;         return  0 ;     }     stack<array<int , 4>> res;     while  ((X != A && X != 0 ) || (Y != B && Y != 0 )) {           int  cx = (X * 2  < A) ? 0  : A;          int  cy = (Y * 2  < B) ? 0  : B;         X = 2  * X - cx;         Y = 2  * Y - cy;         res.push ({ X, Y, cx, cy });     }     cout << res.size () << endl;     while  (!res.empty ()) {         auto  [x1, y1, x2, y2] = res.top ();          res.pop ();         cout << x1 << " "  << y1 << " "  << x2 << " "  << y2 << endl;      }     return  0 ; } 
只有两种情形,一种是第二天某个任务的开始时间和第一天相同,这样从这个任务开始,就会重复前一天的状态,是个循环;另一种是第二天和第一天任务开始时间完全不同,这样任务就会无限期拖延,且每天的拖延时间是相同的。两种都不难计算。
时间复杂度O ( n + q ) \mathcal{O}(n+q) O ( n + q ) 
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #include  <bits/stdc++.h>  using  namespace  std;using  ll = long  long ;int  main ()      ios::sync_with_stdio (false );     cin.tie (nullptr ), cout.tie (nullptr );     int  n, k, q;     cin >> n >> k >> q;     vector<ll> a (n) , b (n)  ;     for  (int  i = 0 ; i < n; i++) {         cin >> a[i] >> b[i];     }     ll now = 0 ;     vector<ll> a1 (n) , a2 (n)  ;     for  (int  i = 0 ; i < n; i++) {         now = a1[i] = max (now, a[i]);         now += b[i];     }     bool  flag = 1 ;       for  (int  i = 0 ; i < n; i++) {         now = a2[i] = max (now, a[i] + k);         now += b[i];         if  (a2[i] == a1[i] + k) {             flag = 0 ;         }     }     ll delta = a2. back () - a1. back ();       while  (q--) {         int  x, i;         cin >> x >> i;         i--;         ll res;         if  (x == 1 ) {             res = a1[i] + b[i] - 1 ;         } else  {             res = a2[i] + b[i] - 1 ;             if  (flag) {                   res += (x - 2ll ) * delta;             } else  {                 res += (x - 2ll ) * k;             }         }         ll d = res / k, h = res % k;         if  (h == 0 ) {             h = k;             d--;         }         cout << (++d) << " "  << h << endl;     }     return  0 ; } 
给定长为N N N A A A Q Q Q i ∈ [ L , R ] i \in [L,R] i ∈ [ L , R ] A i ← A i + v A_i \gets A_i + v A i  ← A i  + v A L , A L + 1 , … , A R A_L, A_{L+1}, \ldots, A_R A L  , A L + 1  , … , A R  ( R − L + 1 ) / 2 (R-L+1)/2 ( R − L + 1 ) / 2 1 ⩽ N , Q , A i , v ⩽ 2 × 1 0 5 1 \leqslant N,Q,A_{i},v \leqslant 2 \times 10^{5} 1 ⩽ N , Q , A i  , v ⩽ 2 × 1 0 5 
设c c c f n f_{n} f n  n n n 
f c + n = f c − n  for all  n ∈ Z f_{c+n} = f_{c-n} \text{for all} n \in \mathbb{Z} f c + n  = f c − n   for all  n ∈ Z 
这就很有幂级数的味道了,考虑形式幂级数
F ( z ) = ∑ n = − ∞ + ∞ z n f n F(z) = \sum_{n=-\infty}^{+\infty} z^{n} f_{n} F ( z ) = n = − ∞ ∑ + ∞  z n f n  
其中z z z 
1 z c F ( z ) = z c F ( z − 1 ) \dfrac{1}{z^{c}} F(z) = z^{c} F(z^{-1}) z c 1  F ( z ) = z c F ( z − 1 ) 
可以随机一个 ULL 哈希值z = x z=x z = x 
具体地,维护区间信息
M + ( z ) = ∑ i = L R z A i , M − ( z ) = ∑ i = L R z − A i , c = 1 R − L + 1 ∑ i = L R A i M_+(z) = \sum_{i=L}^{R} z^{A_i}, \quad M_-(z) = \sum_{i=L}^{R} z^{-A_i}, \quad c = \dfrac{1}{R-L+1} \sum_{i=L}^{R} A_i M +  ( z ) = i = L ∑ R  z A i  , M −  ( z ) = i = L ∑ R  z − A i  , c = R − L + 1 1  i = L ∑ R  A i  
满足条件当且仅当M + ( z ) = z 2 c M − ( z ) M_+(z) = z^{2 c} M_-(z) M +  ( z ) = z 2 c M −  ( z ) 
线段树维护区间乘区间和,复杂度O [ ( N + Q ) log  N ] \mathcal{O}[(N + Q) \log N] O [ ( N + Q ) log  N ] 
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 struct  Lazy  {    Z mul{ 1  };        Z add{ 0  };        void  apply (const  Lazy& o) &          mul *= o.mul;         add = add * o.mul + o.add;     } }; struct  Info  {    Z sum{ 0  };     int  len{ 1  };     void  apply (const  Lazy& o) &          sum *= o.mul;            sum += o.add * len;     } }; Info operator  + (const  Info& L, const  Info& R) {     return  { L.sum + R.sum, L.len + R.len }; } int  main ()      Z po = rnd ();     Z ne = 1  / po;     int  N, Q;     cin >> N >> Q;     vector<Info> a (N) , b (N) , c (N)  ;     for  (auto  n = 0 ; n < N; n++) {         int  x;         cin >> x;         x *= 2 ;         a[n] = { x };         b[n] = { qpow (po, x) };         c[n] = { qpow (ne, x) };     }     LazySegmentTree<Info, Lazy> sumseg (a)  ;     LazySegmentTree<Info, Lazy> poseg (b)  ;     LazySegmentTree<Info, Lazy> neseg (c)  ;     while  (Q--) {         int  op;         cin >> op;                  if  (op == 1 ) {             int  L, R, v;             cin >> L >> R >> v;             L--;             v *= 2 ;             poseg.update (L, R, { qpow (po, v), 0  });             neseg.update (L, R, { qpow (ne, v), 0  });             sumseg.update (L, R, { 1 , v });         } else  {             int  L, R;             cin >> L >> R;             L--;             auto  sum = sumseg.query (L, R).sum;             auto  c = sum / (R - L);             auto  pores = poseg.query (L, R).sum;             auto  neres = neseg.query (L, R).sum;             pores /= qpow (po, c.val ());             neres *= qpow (po, c.val ());             cout << (pores == neres ? "YES"  : "NO" ) << endl;         }     }          return  0 ; } 
游戏有n n n p p p k k k n n n 1 ⩽ n ⩽ 1 0 5 1 \leqslant n \leqslant 10^{5} 1 ⩽ n ⩽ 1 0 5 0 ⩽ k ⩽ 1 0 9 0 \leqslant k \leqslant 10^{9} 0 ⩽ k ⩽ 1 0 9 0 < p ⩽ 0.5 0<p \leqslant 0.5 0 < p ⩽ 0 . 5 n p ⩽ 20 np \leqslant 20 n p ⩽ 2 0 
观察 1:
如果我们拥有无限道具,并且采取一失败就立刻使用道具的策略,通关时道具的期望使用次数为n p 1 − p \dfrac{np}{1-p} 1 − p n p   注意n p ⩽ 20 np \leqslant 20 n p ⩽ 2 0 k k k  事实上,当k > 165 k > 165 k > 1 6 5 n 1 − p \dfrac{n}{1-p} 1 − p n  1 1 − p \dfrac{1}{1-p} 1 − p 1  1 1 − p − 1 = p 1 − p \dfrac{1}{1-p}-1 = \dfrac{p}{1-p} 1 − p 1  − 1 = 1 − p p  n n n n p 1 − p \dfrac{np}{1-p} 1 − p n p  n p 1 − p + n = n 1 − p \dfrac{np}{1-p} + n = \dfrac{n}{1-p} 1 − p n p  + n = 1 − p n   观察 2:
当 “道具数” 较小时,我们会尽可能将道具留到后面的关卡使用 当挑战失败时,我们会决策 是 / 否 使用道具。当 “道具数” 确定时,这一决策是单调的:存在t t t t t t t t t  当k k k f i , j f_{i,j} f i , j  i i i j j j 
如果当前已经通过第j j j j j j j + 1 j + 1 j + 1 
从第j j j j + 1 j+1 j + 1 ( 1 1 − p ) j + 1 {\bigg(\dfrac{1}{1-p}\bigg)}^{j+1} ( 1 − p 1  ) j + 1 
以下给出证明:
若第一次挑战时成功通关,那么次数为1 1 1 1 − p 1-p 1 − p j + 1 j+1 j + 1 
整理一下,现在要求的是 “不使用道具,从第一关开始到第k k k 
设T k T_{k} T k  k k k T k − 1 T_{k-1} T k − 1  k − 1 k - 1 k − 1 k − 1 k-1 k − 1 p p p T k T_{k} T k  1 − p 1-p 1 − p 0 0 0 
T k = T k − 1 + 1 + p T k + ( 1 − p ) 0 T_{k} = T_{k-1}+1+p T_{k}+(1-p) 0 T k  = T k − 1  + 1 + p T k  + ( 1 − p ) 0 
解得
T k = 1 − ( 1 − p ) k p ( 1 − p ) k T_{k} = \dfrac{1-(1-p)^{k}}{p (1-p)^{k}} T k  = p ( 1 − p ) k 1 − ( 1 − p ) k  
所以从第j j j j + 1 j+1 j + 1 
1 + 0 ( 1 − p ) + p T j + 1 = 1 + p 1 − ( 1 − p ) j + 1 p ( 1 − p ) j + 1 = 1 ( 1 − p ) j + 1 1+0 (1-p)+p T_{j+1} = 1+p \dfrac{1-(1-p)^{j+1}}{p (1-p)^{j+1}}=\dfrac{1}{(1-p)^{j+1}} 1 + 0 ( 1 − p ) + p T j + 1  = 1 + p p ( 1 − p ) j + 1 1 − ( 1 − p ) j + 1  = ( 1 − p ) j + 1 1  
所以在不使用道具的情况下,
f i , j = ( 1 1 − p ) j + 1 + f i , j + 1 f_{i,j}=\bigg(\dfrac{1}{1-p}\bigg)^{j+1}+f_{i,j+1} f i , j  = ( 1 − p 1  ) j + 1 + f i , j + 1  
f i , j f_{i,j} f i , j  i i i j j j 
那么当我们在这种状态下再挑战一次,有p p p f i − 1 , j f_{i-1,j} f i − 1 , j  1 − p 1-p 1 − p f i , j + 1 f_{i,j+1} f i , j + 1  
f i , j − 1 = p f i − 1 , j + ( 1 − p ) f i , j + 1 f_{i,j}-1 = p f_{i-1,j} + (1-p) f_{i,j+1} f i , j  − 1 = p f i − 1 , j  + ( 1 − p ) f i , j + 1  
我们也可以设其他状态,比如 “已经使用了i i i j j j 0 0 0 
版本一:f i , j f_{i,j} f i , j  i i i j j j 
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 43 44 45 46 47 48 #include  <bits/stdc++.h>  using  namespace  std;using  ll = long  long ;#define  double long double double  qpow (double  a, ll b)      double  res = 1 ;     while  (b) {         if  (b & 1 ) {             res *= a;         }         b >>= 1 ;         a = a * a;     }     return  res; } int  main ()      ios::sync_with_stdio (false );     cin.tie (0 ), cout.tie (0 );     int  n, k;     cin >> n >> k;     double  p, q;     cin >> p;     q = 1  - p;     cout << fixed << setprecision (12 );     double  ans;     if  (k > 165 ) {         ans = n / (1  - p);         cout << ans << endl;         return ;     }     vector<vector<double >> f (170 , vector <double >(n + 1 ));     for  (int  i = 0 ; i <= k; i++) {         for  (int  j = n - 1 ; j >= 0 ; j--) {             f[i][j] = qpow (1  / q, j + 1 ) + f[i][j + 1 ];             if  (i) f[i][j] = min (1  + p * f[i - 1 ][j] + q * f[i][j + 1 ], f[i][j]);         }     }     ans = f[k][0 ];     cout << ans << endl;     return  0 ; } 
版本二:f i , j f_{i,j} f i , j  i i i j j j 
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 43 44 45 46 47 48 49 #include  <bits/stdc++.h>  using  namespace  std;using  ll = long  long ;#define  double long double double  qpow (double  a, ll b)      double  res = 1 ;     while  (b) {         if  (b & 1 ) {             res *= a;         }         b >>= 1 ;         a = a * a;     }     return  res; } int  main ()      ios::sync_with_stdio (false );     cin.tie (0 ), cout.tie (0 );     int  n, k;     cin >> n >> k;     double  p, q;     cin >> p;     q = 1  - p;     cout << fixed << setprecision (12 );     cerr << fixed << setprecision (12 );     double  ans;     if  (k > 165 ) {         ans = n / (1  - p);         cout << ans << endl;         return ;     }     vector<vector<double >> f (170 , vector <double >(n + 1 ));     for  (int  i = k; i >= 0 ; i--) {         for  (int  j = n - 1 ; j >= 0 ; j--) {             f[i][j] = f[i][j + 1 ] + qpow (1  / q, j + 1 );             if  (i != k) f[i][j] = min (f[i][j], 1  + (1  - p) * f[i][j + 1 ] + p * f[i + 1 ][j]);         }     }     ans = f[0 ][0 ];     cout << ans << endl;     return  0 ; } 
周期是异或的 highbit,复杂度O ( 1 ) \mathcal{O}(1) O ( 1 ) 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include  <bits/stdc++.h>  using  namespace  std;using  ull = unsigned  long  long ;int  main ()      int  T;     cin >> T;     while  (T--) {         ull L, R;         cin >> L >> R;         ull x = 1ULL  << std::__lg(L ^ R);         cout << (L % x) << endl;     }       return  0 ; } 
给定N , K N,K N , K A = ( A 1 , A 2 , … , A N ) A = (A_{1},A_{2},\dots, A_{N}) A = ( A 1  , A 2  , … , A N  ) p 1 , p 2 , … , p N p_{1},p_{2},\dots, p_{N} p 1  , p 2  , … , p N  P i P_{i} P i  i i i K K K ∑ p i = K \sum p_{i} = K ∑ p i  = K K K K S S S S S S ∏ i ∈ S A i \prod_{i\in S} A_{i} ∏ i ∈ S  A i  K < N ⩽ 1 0 5 K<N \leqslant 10^{5} K < N ⩽ 1 0 5 A i ⩽ 1 0 9 A_{i} \leqslant 10^{9} A i  ⩽ 1 0 9 
要求构造p p p 
∏ i ∈ S p i ∏ i ∉ S ( 1 − p i ) ∝ ∏ i ∈ S A i \prod\limits_{i\in S} p_{i}\prod\limits_{i\notin S}(1-p_{i}) \propto \prod\limits_{i\in S} A_{i} i ∈ S ∏  p i  i ∈ / S ∏  ( 1 − p i  ) ∝ i ∈ S ∏  A i  
等价于
p i 1 − p i ∝ A i \dfrac{p_{i}}{1 - p_{i}} \propto A_{i} 1 − p i  p i   ∝ A i  
设比例系数为c c c p i = A i A i + c p_{i}=\dfrac{A_{i}}{A_{i}+c} p i  = A i  + c A i   ∑ p i = K \sum p_{i} = K ∑ p i  = K 
∑ i = 1 N A i A i + c = K . \sum_{i=1}^{N}\frac{A_{i}}{A_{i}+c}=K. i = 1 ∑ N  A i  + c A i   = K . 
这个式子是关于c c c N N N c c c c c c 
复杂度O ( N ( log  V + log  ϵ − 1 ) ) \mathcal{O}(N (\log V + \log \epsilon^{-1})) O ( N ( log  V + log  ϵ − 1 ) ) 
特别注意,浮点数二分在l l l r r r r − l > eps  r-l>\operatorname{eps} r − l > e p s 
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 #include  <bits/stdc++.h>  using  namespace  std;#define  double long double constexpr  double  eps = 1e-18 ;signed  main ()      cout << fixed << setprecision (12 );     int  N, K;     cin >> N >> K;     vector<double > A (N)  ;     for  (int  i = 0 ; i < N; i++) {         cin >> A[i];     }     auto  calc = [&](double  c) {         vector<double > p (N);         for  (int  i = 0 ; i < N; i++) {             p[i] = A[i] / (A[i] + c);         }         return  p;     };     double  l = 0 , r = 1e15 ;     while  (r - l > eps) {         double  mid = (l + r) / 2 ;         auto  p = calc (mid);         if  (accumulate (p.begin (), p.end (), 0.0l ) < K) {             r = mid;         } else  {             l = mid;         }     }     auto  p = calc (l);     for  (int  i = 0 ; i < N; i++) {         cout << p[i] << endl;     }     return  0 ; } 
有三种修改方案:
二分一个在[ 0 , 1 ] [0,1] [ 0 , 1 ] p 1 p_{1} p 1  
判断l l l r r r r − l l \dfrac{r-l}{l} l r − l  
1 2 3 4 5 6 7 8 9 10 double  l = 0 , r = 1e15 ;while  ((r - l) / l > eps) {      double  mid = (l + r) / 2 ;     auto  p = calc (mid);     if  (accumulate (p.begin (), p.end (), 0.0l ) < K) {         r = mid;     } else  {         l = mid;     } } 
控制二分次数:V ⋅ ϵ − 1 = 1 0 15 ⋅ 1 0 18 = 1 0 23 V \cdot \epsilon^{-1}=10^{15}\cdot 10^{18}=10^{23} V ⋅ ϵ − 1 = 1 0 1 5 ⋅ 1 0 1 8 = 1 0 2 3 log  V + log  ϵ − 1 = 76 \log V + \log \epsilon^{-1}=76 log  V + log  ϵ − 1 = 7 6 100 100 1 0 0  1 2 3 4 5 double  l = 0 , r = 1e15 ;for  (int  _ = 0 ; _ < 100 ; _++) {    double  mid = (l + r) / 2 ; } 
这三种都能跑到 100ms 以内。