For the query, I would take a look at how WordPress currently includes sticky posts in the loop. It does a regular query, and then gets the sticky posts in a separate query. If any of the sticky posts exist in the regular query, it is taken out and put at the top. The remaining sticky posts are then also put at the top.
What you should do is query the latest posts, but ignore sticky posts. Then, you query the sticky posts that are less then one month old, ordered by publication date, with a limit of 3. If this results in any posts, you also go through your regular posts to remove any post if it already is one of your sticky posts.
You can prevent the regular query from returning sticky posts by setting the
caller_get_posts option (or
ignore_sticky_posts, as this is called in WP 3.1. The first option was added when sticky posts were added to indicate that the query came from
get_posts(), and thus should ignore sticky posts). To get the sticky posts, you read the post IDs from
get_option( 'sticky_posts' ).