📅  最后修改于: 2023-12-03 15:04:43.126000             🧑  作者: Mango
给定一个长度为n的正整数数组,对于每个询问,给出左右两边界l,r和一个数K,求[l,r]中有多少个数模K的余数是满足[1,p-1]之间。
第一行包含一个整数n,表示数组长度
第二行包含n个空格隔开的整数,表示数列a1,a2,…,an
第三行包含一个整数q,表示询问次数
接下来q行,每行包含三个整数l,r,K,表示一个询问
共q行,每行一个整数,表示相应询问的结果
1≤n,q≤10^5, 1≤ai,K≤10^6, 1≤l,r≤n,
5 1 2 3 4 5 3 1 5 2 2 4 3 3 5 1
2 1 3
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int n, m;
int a[N];
int cnt[N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
scanf("%d", &m);
while (m --)
{
memset(cnt, 0, sizeof cnt);
int l, r, k;
scanf("%d %d %d", &l, &r, &k);
for (int i = l; i <= r; i ++) cnt[a[i] % k] ++;
int res = 0;
for (int i = 1; i < k; i ++) if (cnt[i]) res ++;
printf("%d\n", res);
}
return 0;
}
这道题目就是模模运算和模范围的问题,但是数据范围很大,n和m都是$10^5$,不能直接枚举,考虑如果对于每个询问都去计算[l,r]中的每个数对k的模结果,求余结果,再判断是否在[1,k-1]的区间中,这么算时间复杂度已经达到了$n \cdot m \cdot k$ 左右,显然无法承受。
所以肯定是要找规律减少计算量的,考虑如果我们对数组a中每个数对k的模结果计数,再把有计数的位置加起来,令sum为这个量,那么此时sum就为[l,r]中能够被K整除的数的个数。
因此再来遍历一遍cnt数组,把对应的个数大于0的位置加起来,就是实际上满足条件的数的个数的数量。
最终的时间复杂度就是$n \cdot m$的复杂度,进一步地优化了时间。