blogskol

思わず声に出して読みたくなるブログ

ARC52 D-9

D - 9

K10^{5}より小さい時

桁DPをすればいい
dp[a] [b]:下a桁自由に使えて[値-各桁の和 mod K]がbの時の通り
状態数がK  \log_{10} M、遷移が10なので計算量は10K  \log_{10} M

K10^{5}より大きい時

i1からMまで愚直に回してcheckすればいい
各桁の和 mod K100未満なので、i mod K100になったらiK-100を足していい
K回ごとに100回各桁の和を計算をするので(各桁の和を計算するのに10回として)計算量は\frac{1000M}{K}

#include <bits/stdc++.h>
using namespace std;

#define int long long
int MOD,ans,dp[15][123456];
int pw(int n,int k){
  assert(k>=0);
  int res=1;
  while(k){
    if(k&1)(res*=n)%=MOD;
    (n*=n)%=MOD;
    k>>=1;
  }
  return res;
}

int f(int a,int b){//下a桁自由に使えて、ノーマル側がb先行している時の通り
  if(~dp[a][b])return dp[a][b];
  if(!a)return !b;
  int res=0;
  for(int i=0;i<10;i++)res+=f(a-1,(b+i*pw(10,a-1)+MOD-i)%MOD);
  return dp[a][b]=res;
}

bool g(int a){//愚直
  int res=0,b=a%MOD;
  while(a){
    res+=a%10;
    a/=10;
  }
  return (res%MOD)==b;
}

signed main(){
  memset(dp,-1,sizeof(dp));
  cin>>MOD;

  if(MOD>100000){
    int M;cin>>M;
    for(int i=1;i<=M;i++){
      ans+=g(i);
      if(i%MOD==100)i+=MOD-99;
    }
  }
  else{
    string m;cin>>m;
    int S=m.size(),now=0;
    for(int i=0;i<S;i++){
      int T=pw(10,S-i-1)+MOD-1;
      for(int j=0;j<m[i]-'0';j++){
        ans+=f(S-1-i,now);
        (now+=T)%=MOD;
      }
    }
    ans+=!now;//Mが条件を満たす時
    ans--;//0を除く
  }
  cout<<ans<<endl;
}

Submission #11936944 - AtCoder Regular Contest 052