题意: Jeronimo 先给出 m 个数,然后利用这 m 个数得出剩下的 n-m 个数,具体做法是第 i(i>m) 个数等于第 i-m 个数与第 i-m+1 个数之和对 3×107 取模。
思路: 暴力(产生出 n 个数然后对这 n 个进行排序,然后读取 q 个问题输出)时间复杂度为
O(n+nlogn+q)
会超时,所以我们看到不能直接对这 n 个数进行排序。
可以边产生 n 个数边用一个
3×107
的数组记录下每个数字在 n 个数中出现了几次。
然后记录下问题序列,对问题序列进行排序,复杂度为
O(qlogq)
,由于 q 要比 n 小得多,所以可行。
最后因为已知从小到大每个数字在 n 个数字中出现了几次,所以我们扫一遍问题序列就能够得到相应问题的答案了。
上面思路的时间复杂度大概为
O(n+q+qlogq+kq+q)
,其中的 k 不确定(或者我搞不清楚。。。具体看代码)
代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 3*1e7+10;
const int MOD = 3*1e7;
int n, m, q;
int num[MAXN];
int hs[MAXN];
int b[10010];
int b2[10010];
map<int , int> mp;
int main()
{
while(scanf("%d%d%d", &n, &m, &q) == 3){
memset(hs, 0, sizeof(hs));
mp.clear();
for(int i=0; i<m; i++){
scanf("%d", &num[i]);
hs[num[i]]++;
}
for(int i=m,j=0; i<n; i++,j++){
num[i] = (num[j]+num[j+1])%MOD;
hs[num[i]]++;
}
for(int i=0; i<q; i++){
scanf("%d", &b[i]);
b2[i] = b[i];
}
sort(b2, b2+q);
for(int i=0,sum=0,j=0; i<q; i++){
while(sum < b2[i]){
sum += hs[j++];
}
mp[b2[i]] = j-1;
}
for(int i=0; i<q; i++){
printf("%d\n", mp[b[i]]);
}
}
return 0;
}