公式

H - Simple Division 解説 by en_translator


What information do we need to find the remainder when \(\lfloor N/M \rfloor\) is divided by \(10007\)?

It suffices to find the remainder when \(N\) is divided by \(M \times 10007\). If that remainder is \(r\), the answer is \(\lfloor r/M \rfloor\).
By the constraints, \(M \times 10007 \le 10^9\), we see that \(64\)-bit signed integer is wide enough to compute \({\rm mod}\ (M \times 10007)\).

Here, let \(R_k\) denote the repunit with \(k\) copies of ones. For example, \(R_5=11111\).

We seek for the remainder when the following value is divided by \(M \times 10007\):

  • \(\displaystyle \sum_{i=1}^{N} c_i \times R_{l_i} \times 10^{\sum_{j=i+1}^{N} l_j}\)

All but the repunit part is easy; the problem is the repunit part.
One (common) approach to find the repunit modulo \(X\) is to use the formula \(R_k = \displaystyle \frac{10^{k}-1}{9}\), but in our case the inverse of \(9\) may not exist in \({\rm mod}\ (M \times 10007)\), so this approach is inapplicable. What can we do?

This time, we introduce an algorithm called binary lifting.
The binary lifting is the following algorithm:

  • Using the results on a problem of size \(2^k\), solve the problem of size \(2^{k+1}\). Repeat this until reaching a sufficiently large \(k\).
  • To obtain the results for size \(n\), decompose as \(n = 2^a+2^b+2^c+\dots\) (using its binary representation) and combine the results for power-of-two to solve the size-\(n\) problem.

For details, please refer to the following articles. (They are all in Japanese). There are many other resources on the Internet.

In our case, we can apply binary lifting as follows.

  • Start from \(R_1 = 1\).
  • For \(1 \le k < 30\), obtain \(R_{2^k} = R_{2^{k-1}} \times 10^{2^{k-1}} + R_{2^{k-1}}\).
  • To combine \(R_{2^k}\) to get \(R_n\), when \(R_s\) is known, we can use the formula \(R_{s+2^k} = R_s \times 10^{2^k} + R_{2^k}\).

This way, the repunits modulo \((M \times 10007)\) can be computed without finding the inverse modulo \((M \times 10007)\).
All that left is to evaluate the expression above, and the correct answer can be found.

Sample code (C++):

#include<bits/stdc++.h>

using namespace std;
using ll=long long;

ll mod;

ll power(ll a,ll b){ // a^b
  ll res=1,cur=a;
  while(b>0){
    if(b&1ll){
      res*=cur; res%=mod;
    }
    cur*=cur; cur%=mod;
    b>>=1;
  }
  return res;
}

int main(){
  ll k,m;
  cin >> k >> m;
  mod=(m*10007);
  vector<ll> c(k),l(k);
  for(ll i=0;i<k;i++){
    cin >> c[i] >> l[i];
  }

  vector<ll> pow_keep(30); // 10^{2^d}
  pow_keep[0]=10;
  for(ll d=1;d<30;d++){
    pow_keep[d]=(pow_keep[d-1]*pow_keep[d-1])%mod;
  }

  vector<ll> Rpow2(30);
  Rpow2[0]=1;
  for(ll d=1;d<30;d++){
    Rpow2[d]=(Rpow2[d-1]*pow_keep[d-1]+Rpow2[d-1])%mod;
  }

  ll res=0;
  ll dgt=0;
  for(ll i=k-1;i>=0;i--){
    ll ce=(c[i]*power(10,dgt))%mod;
    ll R=0;
    for(ll d=29;d>=0;d--){
      if(l[i]&(1ll<<d)){
        R=(R*pow_keep[d]+Rpow2[d])%mod;
      }
    }
    res+=ce*R; res%=mod;
    dgt+=l[i];
  }
  cout << res/m << "\n";
  return 0;
}

投稿日時:
最終更新: