use std::io::prelude::*;

fn input<T: std::str::FromStr>() -> T {
    let stdin = std::io::stdin();
    let token: String = stdin
        .lock()
        .bytes()
        .map(|c| c.unwrap() as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().unwrap()
}

fn main() {
    let n: i64 = input();
    let k: i64 = input();

    let mut s = vec![];
    for i in 1.. {
        if i * i > n {
            break;
        }
        s.push(i);
        s.push(n / i);
    }
    s.sort();
    s.dedup();

    let m = s.len();
    let mut w = vec![1; m];
    for i in 0..m - 1 {
        w[i] = n / s[i] - n / s[i + 1];
    }

    let mut dp = vec![vec![ModInt(0); m]; k as usize + 1];
    dp[0][m - 1] += 1;
    for i in 0..k as usize {
        for j in (0..m - 1).rev() {
            dp[i][j] += dp[i][j + 1];
        }
        for j in 0..m {
            let nj = s.lower_bound(n / s[j]);
            dp[i + 1][j] += dp[i][nj] * w[j];
        }
    }

    let mut ans = ModInt(0);
    for j in 0..m {
        ans += dp[k as usize][j];
    }
    println!("{}", ans);
}

trait LowerBound<T: Ord> {
    fn lower_bound(&self, x: T) -> usize;
}

impl<T: Ord> LowerBound<T> for [T] {
    fn lower_bound(&self, x: T) -> usize {
        let mut l = -1 as i64;
        let mut r = self.len() as i64;
        while r - l > 1 {
            let m = ((l + r) / 2) as usize;
            if self[m] >= x {
                r = m as i64;
            } else {
                l = m as i64;
            }
        }
        r as usize
    }
}

const MOD: i64 = 1000000007;

#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct ModInt(i64);

impl ModInt {
    fn new(x: i64) -> ModInt {
        ModInt(x % MOD)
    }
}

impl std::fmt::Display for ModInt {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.0.fmt(f)
    }
}

impl std::ops::Add for ModInt {
    type Output = ModInt;
    fn add(self, other: ModInt) -> ModInt {
        let mut x = self;
        x += other;
        x
    }
}

impl std::ops::Mul for ModInt {
    type Output = ModInt;
    fn mul(self, other: ModInt) -> ModInt {
        let mut x = self;
        x *= other;
        x
    }
}

impl std::ops::Sub for ModInt {
    type Output = ModInt;
    fn sub(self, other: ModInt) -> ModInt {
        let mut x = self;
        x -= other;
        x
    }
}

impl std::ops::AddAssign for ModInt {
    fn add_assign(&mut self, other: ModInt) {
        self.0 += other.0;
        if self.0 >= MOD {
            self.0 -= MOD;
        }
    }
}

impl std::ops::MulAssign for ModInt {
    fn mul_assign(&mut self, other: ModInt) {
        self.0 *= other.0;
        self.0 %= MOD;
    }
}

impl std::ops::SubAssign for ModInt {
    fn sub_assign(&mut self, other: ModInt) {
        self.0 += MOD - other.0;
        if self.0 >= MOD {
            self.0 -= MOD;
        }
    }
}

impl<T: Into<i64>> std::ops::Add<T> for ModInt {
    type Output = ModInt;
    fn add(self, other: T) -> ModInt {
        self + ModInt::new(other.into())
    }
}

impl<T: Into<i64>> std::ops::Mul<T> for ModInt {
    type Output = ModInt;
    fn mul(self, other: T) -> ModInt {
        self * ModInt::new(other.into())
    }
}

impl<T: Into<i64>> std::ops::Sub<T> for ModInt {
    type Output = ModInt;
    fn sub(self, other: T) -> ModInt {
        self - ModInt::new(other.into())
    }
}

impl<T: Into<i64>> std::ops::AddAssign<T> for ModInt {
    fn add_assign(&mut self, other: T) {
        *self += ModInt::new(other.into());
    }
}

impl<T: Into<i64>> std::ops::MulAssign<T> for ModInt {
    fn mul_assign(&mut self, other: T) {
        *self *= ModInt::new(other.into());
    }
}

impl<T: Into<i64>> std::ops::SubAssign<T> for ModInt {
    fn sub_assign(&mut self, other: T) {
        *self -= ModInt::new(other.into());
    }
}


Measured memory_bytes: 73980