noip模拟赛 洗澡
分析:首先肯定是要用线性筛把素数全部给筛出来的,然后可以维护一个前缀和数组记录1~i个素数的和,对于每一个询问可以从n到1+k枚举它的右端点,然后利用前缀和统计一个长度为K的区间和,看看是不是满足条件.其实这个可以利用二分来加速,然后就做完了.
二分的时候如果有多个条件需要满足,可以拆分开来讨论l,r怎么移动,最好不要挤在一起写.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; int T, n, k, prime[1000010], cnt, vis[1000010]; ll sum[1000010]; void init() { for (int i = 2; i <= 1000000; i++) { if (!vis[i]) prime[++cnt] = i; for (int j = 1; j <= cnt; j++) { int t = prime[j] * i; if (t > 1000000) break; vis[t] = 1; if (i % prime[j] == 0) break; } } for (int i = 1; i <= cnt; i++) sum[i] = sum[i - 1] + prime[i]; } void solve(int x, int y) { int l = 1, r = cnt, ans = -1; while (l <= r) { int mid = (l + r) >> 1; if (mid < k) l = mid + 1; else if (sum[mid] - sum[mid - k] > n) r = mid - 1; else if (mid >= k && sum[mid] - sum[mid - k] <= n) { l = mid + 1; ans = mid; } } if (ans == -1) printf("-1\n"); else printf("%lld\n", sum[ans] - sum[ans - k]); } int main() { init(); scanf("%d", &T); while (T--) { scanf("%d%d", &n, &k); solve(n, k); } return 0; }