12 月上旬算法题集。
 
 
    
    
First One HDU - 5358  
For each i, merge those j’s such that $[\log_2S(i, j)]$ get the same value. At most $\log_2(n·1e5)$ values will $[\log_2S(i, j)]$ have. 
By using Prefix Sum and Binary Search, we can find those j’s in $O(log(n))$ .
The total time complexity is $O(n\log_2(n·1e5)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 #include <bits/stdc++.h>  #define  int long long using  namespace  std;inline  int  read ()  {    int  x = 0 , f = 1 ; char  ch = getchar ();     while (ch < '0'  || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); }     while (ch >= '0'  && ch <= '9' ) { x = x * 10  + ch - 48 ; ch = getchar (); }     return  x * f; } int  lg (int  x)  {    if (x == 0 ) return  0 ;     return  63  - __builtin_clzll(x); }  void  solve ()  {    int  n = read (), res = 0 ;     vector<int >v (n + 1 , 0 );     for (int  i = 1 ; i <= n; i++){         v[i] = v[i - 1 ] + read ();     }          for (int  i = 1 ; i <= n; i++){         int  ll = i - 1 ;         for (int  k = lg (v[i] - v[i - 1 ]); k <= lg (v[n]); k++){             int  l = ll, r = n + 1 ;             while (l + 1  != r){                 int  mid = l + r >> 1 ;                 if (v[mid] - v[i - 1 ] < (1ll  << (k + 1 ))) l = mid;                 else  r = mid;             }             res += (k + 1 ) * (i * (l - ll) + (ll + l + 1 ) * (l - ll) / 2 );             ll = l;         }     }     cout << res << '\n' ; } signed  main ()  {    int  t = read ();     while (t--) solve ();     return  0 ; } 
 
Trapped in the Witch’s Labyrinth Codeforces Round 989 div1+2 C 
Let’s consider those cells that can definitely escape:there must be a path leading to the border.
Thus, we can use a DFS in a reversed way, starting from points on the border(artificially added), recursively finding all cells that can escape from the boundary points.
Don’t forget, if a unspecified cell is surrounded by four points that can escape, it will exit too.
It’s easy to prove that, there is always a way to make the remaining cells being trapped forever: Two cells:point to each other. More cells:point to the two cells.
Implementation:
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 #include <bits/stdc++.h>  #define  int long long using  namespace  std;const  int  N = 1000 ;vector<vector<char >>mp (N + 2 , vector <char >(N + 2 )); vector<vector<int >>vis (N + 2 , vector <int >(N + 2 , 0 )); int  cnt, n, m;void  dfs (int  x, int  y)   {    vis[x][y] = 1 ;     if  (x == 0 ) {         if  (mp[x + 1 ][y] == 'U'  && !vis[x + 1 ][y]) dfs (x + 1 , y);     }     else  if  (x == n + 1 ) {         if  (mp[x - 1 ][y] == 'D'  && !vis[x - 1 ][y]) dfs (x - 1 , y);     }     else  if  (y == 0 ) {         if  (mp[x][y + 1 ] == 'L'  && !vis[x][y + 1 ]) dfs (x, y + 1 );     }     else  if  (y == m + 1 ) {         if  (mp[x][y - 1 ] == 'R'  && !vis[x][y - 1 ]) dfs (x, y - 1 );     }     else  {         cnt++;         if  (mp[x + 1 ][y] == 'U'  && !vis[x + 1 ][y]) dfs (x + 1 , y);         if  (mp[x - 1 ][y] == 'D'  && !vis[x - 1 ][y]) dfs (x - 1 , y);         if  (mp[x][y + 1 ] == 'L'  && !vis[x][y + 1 ]) dfs (x, y + 1 );         if  (mp[x][y - 1 ] == 'R'  && !vis[x][y - 1 ]) dfs (x, y - 1 );     } } void  solve ()   {    cnt = 0 ;     cin >> n >> m;          for (int  i = 0 ; i <= n + 1 ; i++){         for (int  j = 0 ; j <= m + 1 ; j++){             mp[i][j] = '0' ;             vis[i][j] = 0 ;         }     }     for  (int  i = 1 ; i <= n; i++) {         for  (int  j = 1 ; j <= m; j++) {             cin >> mp[i][j];             vis[i][j] = 0 ;         }     }     for  (int  j = 1 ; j <= m; j++) {         dfs (0 , j), dfs (n + 1 , j);     }     for  (int  i = 1 ; i <= n; i++) {         dfs (i, 0 ), dfs (i, m + 1 );     }     for  (int  i = 1 ; i <= n; i++) {         for  (int  j = 1 ; j <= m; j++) {             if  (mp[i][j] == '?'  && vis[i - 1 ][j] && vis[i + 1 ][j] && vis[i][j - 1 ] && vis[i][j + 1 ])                 vis[i][j] = 1 , cnt++;         }     }     cout << n * m - cnt << '\n' ; } signed  main ()   {    ios::sync_with_stdio (0 );     cin.tie (0 );     int  t; cin >> t;     while  (t--) solve ();     return  0 ; } 
 
Darius’ Wisdom Codeforces Round 989 div1+2 D 
Construction problem.
We can easily find the final condition of the array. Then do the following steps:
Put every 0 in its right position. Since 1 always exsits, by using 1, it takes at most 2count(0) steps. 
The rest of array only contains 1 and 2. To sort this part of array, we need at most min(count(1), count(2)) steps. 
 
2count(0) + min(count(1), count(2)) is certainly too much, we need to lower it to less than n.
Assume we have count(0) <= count(2)(0 and 2 are equivalent, if not satisfied,  just exchange 0 and 2 is ok)
Through mathematical calculations 2count(0) + min(count(1), count(2)) <= count(0) + max(count(1), count(2)) + min(count(1) + count(2)) = count(0) + count(1) + count(2) = n
Implementation:
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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 #include <bits/stdc++.h>  using  namespace  std;typedef  pair<int , int > PII;inline  int  read ()   {    int  x = 0 , f = 1 ; char  ch = getchar ();     while  (ch < '0'  || ch > '9' ) { if  (ch == '-' ) f = -1 ; ch = getchar (); }     while  (ch >= '0'  && ch <= '9' ) { x = x * 10  + ch - 48 ; ch = getchar (); }     return  x * f; } void  solve ()   {    int  n = read ();      int  x = 0 , y = 0 , z = 0 , pos;     vector<int >v (n + 1 );     for  (int  i = 1 ; i <= n; i++) {         v[i] = read ();         if (v[i] == 0 ) x++;         if (v[i] == 1 ) y++, pos = i;         if (v[i] == 2 ) z++;     }     int  cnt = 0 ;     vector<PII>res;          if (x <= z){         for (int  i = 1 , j = x + 1 ;;){             while (i <= x && v[i] == 0 ){                 i++;             }             while (j <= n && v[j] != 0 ){                 j++;             }             if (i > x || j > n) break ;             if (v[i] == 1 ){                 cnt++;                 swap (v[i], v[j]);                 res.emplace_back (i, j);                 pos = j;              }             else  if (v[i] == 2 ){                 cnt += 2 ;                 swap (v[i], v[pos]);                 swap (v[i], v[j]);                 res.emplace_back (i, pos);                 res.emplace_back (i, j);                 pos = j;             }         }         for (int  i = x + 1 , j = x + y + 1 ;;){             while (i <= x + y && v[i] == 1 ){                 i++;             }             while (j <= n && v[j] == 2 ){                 j++;             }             if (i > x + y || j > n) break ;             cnt++;             swap (v[i], v[j]);             res.emplace_back (i, j);         }     }     else {         for (int  i = x + y + 1 , j = 1 ;;){             while (i <= n && v[i] == 2 ){                 i++;             }             while (j <= x + y && v[j] != 2 ){                 j++;             }             if (i > n || j > x + y) break ;             if (v[i] == 1 ){                 cnt++;                 swap (v[i], v[j]);                 res.emplace_back (i, j);                 pos = j;              }             else  if (v[i] == 0 ){                 cnt += 2 ;                 swap (v[i], v[pos]);                 swap (v[i], v[j]);                 res.emplace_back (i, pos);                 res.emplace_back (i, j);                 pos = j;             }         }         for (int  i = x + 1 , j = 1 ;;){             while (i <= x + y && v[i] == 1 ){                 i++;             }             while (j <= x && v[j] == 0 ){                 j++;             }             if (i > x + y || j > x) break ;             cnt++;             swap (v[i], v[j]);             res.emplace_back (i, j);         }     }     cout << cnt << '\n' ;     for (auto  &u : res){         cout << u.first << ' '  << u.second << '\n' ;     } } signed  main ()   {    int  t = read ();     while  (t--) solve ();     return  0 ; } 
 
Recommendations Educational Codeforces Round 172 (div.2) D 
For each segment, we need to find the minimum l and the maximum r of its predictor.
The first round, sort the segments in l ascending , r descending order. Using Binary Search to find the min{r} of one’s predictors. Then add its r into the set. In this way, we can always find the  min{r} of each segment.
The second round, sort the segments in r descending, l ascending order. With similar handling method, we can find the  max{l} of each segment.
Pay attention to the situation that serveral segments are exactly the same: we need to help the first handled segment to change its max{l} and min{r} to l and r of its own.
Implementation:
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 #include <bits/stdc++.h>  using  namespace  std;typedef  pair<int , int >PII;inline  int  read ()  {    int  x = 0 , f = 1 ; char  ch = getchar ();     while (ch < '0'  || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); }     while (ch >= '0'  && ch <= '9' ) { x = x * 10  + ch - 48 ; ch = getchar (); }     return  x * f; } void  solve ()  {    int  n = read ();     vector<int >l (n), r (n);     for (int  i = 0 ; i < n; i++){         l[i] = read (), r[i] = read ();     }     vector<int > L (n, -1 ) , R (n, -1 )  ;     vector<int > p (n)  ;     iota (p.begin (), p.end (), 0 );          {         sort (p.begin (), p.end (), [&](int  i, int  j){             if (l[i] != l[j]) return  l[i] < l[j];             return  r[i] > r[j];         });                  set<int > s;         for (int  j = 0 ; j < n; j++){             int  i = p[j];             auto  it = s.lower_bound (r[i]);             if (it != s.end ()){                 R[i] = *it;             }             if (j + 1  < n && l[i] == l[p[j + 1 ]] && r[i] == r[p[j + 1 ]]){                 R[i] = r[i];             }             s.emplace (r[i]);         }     }          {         sort (p.begin (), p.end (), [&](int  i, int  j){             if (r[i] != r[j]) return  r[i] > r[j];             return  l[i] < l[j];         });                  set<int > s;         for (int  j = 0 ; j < n; j++){             int  i = p[j];             auto  it = s.upper_bound (l[i]);             if (it != s.begin ()){                 L[i] = *prev (it);             }             if (j + 1  < n && l[i] == l[p[j + 1 ]] && r[i] == r[p[j + 1 ]]){                 L[i] = l[i];             }             s.emplace (l[i]);         }     }          for (int  i = 0 ; i < n; i++){         if (L[i] == -1 ){             cout << 0  << '\n' ;         }         else {             cout << (R[i] - L[i]) - (r[i] - l[i]) << '\n' ;          }     } } signed  main ()  {    int  t = read ();     while (t--) solve ();     return  0 ; } 
 
Move Back at a Cost Codeforces Round 990 div1 B (div2 D) 
Ascending array (call it stk) should be saved.
The rest elements (call it b) should be put back in ascending order, and when the tail of stk is smaller then the head of b, it should also join b and finally be put in the back of array.
Implementation:
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 #include <bits/stdc++.h>  #define  int long long using  namespace  std;inline  int  read ()  {    int  x = 0 , f = 1 ; char  ch = getchar ();     while (ch < '0'  || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); }     while (ch >= '0'  && ch <= '9' ) { x = x * 10  + ch - 48 ; ch = getchar (); }     return  x * f; } void  solve ()  {    int  n = read ();     vector<int >a (n);     for (auto  &i : a) i = read ();          vector<int >stk, b;     for (int  i = 0 ; i < n; i++){         while (!stk.empty () && stk.back () > a[i]){             b.emplace_back (stk.back () + 1 );             stk.pop_back ();         }         stk.emplace_back (a[i]);     }     sort (b.begin (), b.end ());          while (!b.empty () && stk.back () > b[0 ]){         b.emplace_back (stk.back () + 1 );         stk.pop_back ();     }     sort (b.begin (), b.end ());          a = stk;     for (auto  &i : b) a.emplace_back (i);     for (int  i = 0 ; i < n; i ++){         cout << a[i] << " \n" [i == n - 1 ];     } } signed  main ()  {    int  t = read ();     while (t--) solve ();     return  0 ; } 
 
Expansion Packs Atcoder ABC 382 E 
dp[i] means the probability to get i rare cards in one pack. Not difficult to update dp[i] by the given probabilities. (Refering the implementation)
f[x] means the expected number to get x rare cards.
If i <= 0 , f[i] = 0. The recurrence formula: $$ f[x]=\sum_{i=0}^ndp[i]\times(1+f[x-i]) $$ That is: $$ f[x]=\frac{1+\sum_{i=1}^ndp[i]\times f[x-i]}{1-dp[0]} $$ Implementation:
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 #include <bits/stdc++.h>  using  namespace  std;void  solve ()  {    int  n, x; cin >> n >> x;     vector<double >dp (n + 1 , 0 ); dp[0 ] = 1 ;     for (int  i = 0 ; i < n; i++){         int  q; cin >> q;         double  p = 0.01  * q;         for (int  j = i; j >= 0 ; j--){             dp[j + 1 ] += dp[j] * p;             dp[j] *= 1  - p;         }     }     double  s = 1  - dp[0 ];       vector<double > f (x + 1 )  ;       for  (int  i = 1 ; i <= x; i++) {         for  (int  j = 1 ; j <= n; j++) {                f[i] += f[max (i - j, 0 )] * dp[j];         }         f[i] += 1 ;           f[i] /= 1  - dp[0 ];     }       cout << fixed << setprecision (17 ) << f[x] << '\n' ; } signed  main ()  {    ios::sync_with_stdio (0 );     cin.tie (0 );     int  t = 1 ;     while (t--) solve ();     return  0 ; } 
 
9 Divisors Atcoder ABC 383 D 
$9=(1+8)=(1+2)*(1+2)$
It means if a number has 9 divisors, it can be expressed by $p_1^8$ or $p_1^2p_2^2$ 
($p_i$ is a random prime number)
Init all the satisfied number and use binary search to get the answer.
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 #include <bits/stdc++.h>  #define  int long long using  namespace  std;inline  int  read ()  {    int  x = 0 , f = 1 ; char  ch = getchar ();     while (ch < '0'  || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); }     while (ch >= '0'  && ch <= '9' ) { x = x * 10  + ch - 48 ; ch = getchar (); }     return  x * f; } const  int  MX = 4e12 ;const  int  N = 2e6 +5 ;int  primes[N], cnt;bool  comp[N];vector<int >v; void  Euler (int  n)  {    for (int  i = 2 ; i <= n; i++){         if (!comp[i]) primes[cnt++] = i;         for (int  j = 0 ; primes[j] <= n / i; j++){             comp[i * primes[j]] = 1 ;             if (!(i % primes[j])) break ;         }     } } void  init ()  {    Euler (2000000 );     for (int  i = 2 ; i < 40 ; i++){         if (comp[i]) continue ;         int  u = i * i * i * i * i * i * i * i;         if (u <= MX){             v.emplace_back (u);                      }     }     for (int  i = 0 ; i < cnt; i++){         if (primes[i] > 2000 ) break ;         for (int  j = i + 1 ; j < cnt; j++){             int  u = primes[i] * primes[i] * primes[j] * primes[j];             if (u > MX) break ;             v.emplace_back (u);                      }     }     sort (v.begin (), v.end ()); } void  solve ()  {    int  n = read ();     cout << upper_bound (v.begin (), v.end (), n) - v.begin (); } signed  main ()  {    init ();      solve ();     return  0 ; } 
 
阿兔与种树 牛客 - 浙江机电职业技术大学第九届程序设计竞赛 J 
每次修改在原序列 s 上放入一个等差数列 1, 2, ... , n。
不妨考察其差分形式 1, 1, ... , 1, -n
依然不方便整体修改,继续考察差分数列的差分 1, 0, ..., 0, -n - 1, 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 #include <bits/stdc++.h>  #define  int long long using  namespace  std;inline  int  read ()  {    int  x = 0 , f = 1 ; char  ch = getchar ();     while (ch < '0'  || ch > '9' ) { if (ch == '-' ) f = -1 ; ch = getchar (); }     while (ch >= '0'  && ch <= '9' ) { x = x * 10  + ch - 48 ; ch = getchar (); }     return  x * f; } signed  main ()  {    int  n = read (), m = read ();     vector<int >dd (n + 3 , 0 ), d (n + 3 , 0 ), s (n + 3 , 0 );     for (int  i = 0 ; i < m; i++){         int  l = read (), r = read ();         dd[l]++;         dd[r + 1 ] -= r - l + 2 ;         dd[r + 2 ] += r - l + 1 ;     }     for (int  i = 1 ; i <= n; i++){         d[i] = d[i - 1 ] + dd[i];     }     for (int  i = 1 ; i <= n; i++){         s[i] = s[i - 1 ] + d[i];     }     for (int  i = 1 ; i <= n; i++){         cout << s[i] << ' ' ;     }     return  0 ; }