Since your 'ugly' url does not use the title, you can simply match it, but ignore it. You are currently matching 1/hello-world in your first capture group, and your post.php page can obviously not handle this. Instead match the following:
RewriteRule ^blog/([^/]+)/[^/]+$ post.php?id=$1 [L]
Edit: Someone claims that this approach is inefficient. I beg to differ. You can do the following in php to redirect requests that were done using an incorrect url. It's exactly as efficient as a comparison of $_GET['title'] and $expectedtitle, then constructing the url. The difference is that you have no useless variables lying around, and the intention of this code is clear. You want to redirect the user if the url is not the expected url. That the expected title is not the actual title is a sideproduct.
$expectedtitle = getTitleById( $_GET['id'] );
$expectedurl = "{$_GET['id']}/{$expectedtitle}";
if( $_SERVER['REQUEST_URI'] != $expectedurl ) {
header( $expectedurl, TRUE, 301 );
}