题意:给一个长度为n的数组,进行p次询问。每次询问输入两个数a,b,输出数组中第a位开始,每隔b位的所有数字之和。(1<=n,p<=3*10^5)
解法:刚看清题意,一直在考虑是不是有什么特殊的数据结构,可以把每次查询的时间复杂度降到O(logn)。但其实仔细分析可以发现如果b>=600,那每次查询最多只需要取500个数字。如果测试数据b都大于600,那么时间复杂度是O(500*p),可以在限定时间内完成。就是说如果b>=600,我们只需要直接计算就好了。如果b<600,我们可以离线查询。对每一组b相同的查询,我们只需要O(n)的时间就能完成。所以这一步的时间复杂度是O(600*n)。总时间复杂度是O(500*p+600*n)。
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #include <memory.h> #include <string> #include <vector> #include <map> #include <set> #include <algorithm> #include <iostream> #define lint __int64 using namespace std; const int N = 300005; const int M = 600; vector< pair<int, int> > V[M]; int mass[N]; lint sum[N], res[N]; int main() { int n, m, a, b, i, j; scanf("%d", &n); for (i = 1; i <= n; i++) scanf("%d", mass + i); scanf("%d", &m); for (i = 0; i < M; i++) V[i].clear(); for (i = 1; i <= m; i++) { scanf("%d %d", &a, &b); if (b >= M) { res[i] = 0; for (j = a; j <= n; j += b) res[i] += mass[j]; } else { V[b].push_back(make_pair(i, a)); } } for (i = 1; i < M; i++) { if (!V[i].empty()) { for (j = n; j >= 1; j--) { sum[j] = mass[j]; if (i + j <= n) sum[j] += sum[j+i]; } for (j = 0; j < V[i].size(); j++) { res[V[i][j].first] = sum[V[i][j].second]; } } } for (i = 1; i <= m; i++) printf("%I64d\n", res[i]); return 0; }