为了不断优化推荐效果,今日头条每天要存储和处理海量数据。假设有这样一种场景:我们对用户按照它们的注册时间先后来标号,对于一类文章,每个用户都有不同的喜好值,我们会想知道某一段时间内注册的用户(标号相连的一批用户)中,有多少用户对这类文章喜好值为k。因为一些特殊的原因,不会出现一个查询的用户区间完全覆盖另一个查询的用户区间(不存在L1<=L2<=R2<=R1)。
为了不断优化推荐效果,今日头条每天要存储和处理海量数据。假设有这样一种场景:我们对用户按照它们的注册时间先后来标号,对于一类文章,每个用户都有不同的喜好值,我们会想知道某一段时间内注册的用户(标号相连的一批用户)中,有多少用户对这类文章喜好值为k。因为一些特殊的原因,不会出现一个查询的用户区间完全覆盖另一个查询的用户区间(不存在L1<=L2<=R2<=R1)。
输入: 第1行为n代表用户的个数 第2行为n个整数,第i个代表用户标号为i的用户对某类文章的喜好度 第3行为一个正整数q代表查询的组数 第4行到第(3+q)行,每行包含3个整数l,r,k代表一组查询,即标号为l<=i<=r的用户中对这类文章喜好值为k的用户的个数。 数据范围n <= 300000,q<=300000 k是整型
输出:一共q行,每行一个整数代表喜好值为k的用户的个数
5 1 2 3 3 5 3 1 2 1 2 4 5 3 5 3
1 0 2
样例解释: 有5个用户,喜好值为分别为1、2、3、3、5, 第一组询问对于标号[1,2]的用户喜好值为1的用户的个数是1 第二组询问对于标号[2,4]的用户喜好值为5的用户的个数是0 第三组询问对于标号[3,5]的用户喜好值为3的用户的个数是2
n = int(input()) #这道题用暴搜肯定超时,但是用Python的字典会非常简单 user_array = list(map(int,input().strip().split())) user_dict = dict() #创建一个字典 for i in range(len(user_array)): #对应的键值是用户喜爱程度,value值是一个列表,对应相应的用户id if user_dict.__contains__(user_array[i]): user_array_list_i = list(user_dict[user_array[i]]) user_array_list_i.append(i+1) user_dict[user_array[i]] = user_array_list_i else: user_array_list_i = [] user_array_list_i.append(i+1) user_dict[user_array[i]] = user_array_list_i q = int(input()) for i in range(q): query = list(map(int,input().strip().split())) start_index = query[0] end_index = query[1] k = query[2] if user_dict.__contains__(k): query_list = user_dict[k] #通过键值找到这个喜爱程度对应所有的用户id count = 0 for j in range(len(query_list)): if start_index <= query_list[j] <= end_index: count += 1 print(count) else: print(0)
<?php// 已通过所有用例functiongetArrFromLine($pattern,$split,$num) {$arr= [];$p_str= "";for($i= 0; $i<$num; $i++) {if($i!= $num-1){$p_str.= "{$pattern}{$split}";}else{$p_str.= "{$pattern}\n";}//$arr[$i] = null;}$paramters= [STDIN,$p_str];for($i= 0; $i<$num; $i++) {$paramters[$i+2] = &$arr[$i];}call_user_func_array('fscanf',$paramters);return$arr;}fscanf(STDIN, "%d",$users);$karr= getArrFromLine("%d"," ",$users);$kmap= [];for($i=0;$i<$users;$i++) {$k= $karr[$i];if(isset($kmap[$k]) && is_array($kmap[$k])) {array_push($kmap[$k],$i+1);}else{$kmap[$k] = [$i+1];}}//print_r($kmap);fscanf(STDIN, "%d",$groups);$res= [];for($i=0; $i<$groups; $i++) {$res[$i] = 0;list($start_id,$end_id,$k) = getArrFromLine("%d"," ",3);if(is_array($kmap[$k])) {foreach($kmap[$k] as$uid) {if($start_id<=$uid&& $uid<=$end_id)$res[$i]++;}}}foreach($resas$r) {echo$r,"\n";}?>
#include <bits/stdc++.h> using namespace std; int main(){ int n, q, l, r, k; scanf("%d", &n); int a[n+1]; map<int, vector<int>> mp; for(int i=1;i<=n;i++){ scanf("%d", &a[i]); mp[a[i]].push_back(i); } scanf("%d", &q); for(int i=0;i<q;i++){ scanf("%d%d%d", &l, &r, &k); if(mp.find(k) == mp.end()) puts("0"); else{ auto v = mp[k]; auto ll = lower_bound(v.begin(), v.end(), l); auto rr = upper_bound(v.begin(), v.end(), r); printf("%ld\n", rr-ll); } } return 0; }
#include <iostream> #include <unordered_map> #include <vector> #include <algorithm> using namespace std; int main() { int n; cin >> n; unordered_map<int,vector<int>> kMapUser; for (int i = 0; i < n; i++) { int kValue; cin >> kValue; kMapUser[kValue].push_back(i+1); //向量中的元素自动有序,这点很好 } int q; cin >> q; for (int i = 0; i < q; i++) { int startUserIndex, endUserIndex, kvalue; cin >> startUserIndex >> endUserIndex >> kvalue; auto users = kMapUser[kvalue]; auto low = lower_bound(users.begin(), users.end(), startUserIndex); auto high = upper_bound(users.begin(), users.end(), endUserIndex); cout << high - low << endl; } //system("Pause"); return 0; }
//线段树区间查询(超时) int layer, sum, first, last; //层数,总结点数,子节点下标起点、终点 int ql, qr, qt; //查询范围的起点终点的真实下标 map<pair<pair<int,int>,int>, int> history; //历史查询记录 //传入元素个数,初始化满二叉树参数,返回总结点数 int init(int n){ sum = 1, layer=1; int tmp = 1; //满二叉树页节点的个数 while (tmp < n){ tmp *= 2; sum += tmp; layer++; } sum = sum - tmp + n; first = pow(2, layer - 1) - 1; last = first + n -1; //失误:漏了-1 return sum; } //i:当前节点下标,返回能到达的叶子节点左边界 int getLeft(int i){ while (i < first){ i = i * 2 + 1; } return i; } //i:当前节点下标,返回能到达的叶子节点右边界 int getRight(int i){ while (i < first){ i = i * 2 + 2; } return i; } //查询函数,i:当前节点所在下标 int Query(int i){ if (i >= first){ //叶子节点 if (i >= ql && i <= qr){ //重大失误:没有判断i是否在查询的范围! return history[{{i, i},qt}]; } return 0; } int lr = getLeft(i); int rr = getRight(i); if (rr < ql || lr > qr){ //与查询边界没有交集 return 0; } if (lr >= ql && rr <= qr){ //完全包含在查询边界里 if (history.find({ { lr, rr } , qt}) != history.end()){//已有记录 return history[{{lr, rr}, qt}]; } int total = Query(i * 2 + 1) + Query(i * 2 + 2); history.insert({ { { lr, rr } ,qt}, total}); return total; } return Query(i * 2 + 1) + Query(i * 2 + 2); } int main(){ int n; cin >> n; init(n); //为子节点赋值 for (int i = 0; i < n; i++){ int t; scanf("%d", &t); history.insert({ { { first + i, first + i }, t }, 1 }); } //开始查询 cin >> n; while (n--){ scanf("%d %d %d", &ql, &qr, &qt); ql = ql + first - 1; qr = qr + first - 1; cout << Query(0) << endl; } return 0; }
N=int(input()) s=list(map(int,input().split())) user_dict={} #建立空的dict for x in range(N): if user_dict.__contains__(s[x]): #如果包含该key,则直接向value追加数据。value里面是list user_dict[s[x]].append(x+1) else: user_dict[s[x]]=[x+1] #如果不包含该key,添加。 M=int(input()) for x in range(M): [l,r,k]=list(map(int,input().split())) #边循环,边处理 result = 0 if user_dict.__contains__(k): for y in user_dict[k]: if l<=y<=r: result+=1 print(result)
#include <iostream> #include <vector> #include <map> using namespace std; int main(int argc, char *argv[]) { int i, j, n, k, l, r, q, input, cnt; map <int, vector<int> >hobby; vector<int> tmp; cin >> n; for(i = 1; i <= n; i++) { cin >> input; //这里输入的就是所有出现的喜好值 if(hobby.count(input) == 0) //如果喜好值没有出现过 { tmp.clear();//注意这行的作用,因为某次循环中,tmp可能是上一次循环的tmp,即tmp不为空,所以要先清空 tmp.push_back(i); hobby[input] = tmp; tmp.clear(); } else { tmp = hobby[input]; tmp.push_back(i); hobby[input] = tmp; //覆盖原来的键值 } } cin >> q; while(q--) { cin >> l >> r >> k; cnt = 0; if(hobby.count(k)) //这个喜好值在map中 { tmp = hobby[k]; j = tmp.size(); for(i = 0; i < j; i++) //计算有多少个用户编号在范围内 { if(tmp[i] >= l && tmp[i] <= r) { cnt++; } } } cout << cnt << endl; } return 0; }
直接在数组中进行判断有几个的,但是不知道数据大的时候,牛客上怎么就ac了,有点奇怪
import java.util.Scanner;
/**
* @Auther: xuzhangwang
* @Description:
*/
public class Main {
static int[] arr;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
arr = new int[n + 1];
for (int i = 1; i < n + 1; i++) {
arr[i] = sc.nextInt();
}
int q = sc.nextInt();
for (int i = 0; i < q; i++) {
int l = sc.nextInt();
int r = sc.nextInt();
int k = sc.nextInt();
check(arr, l, r, k);
}
}
private static void check(int[] arr, int l, int r, int k) {
int ans = 0;
for (int i = l; i <= r; i++) {
if (arr[i] == k) {
ans++;
}
}
System.out.println(ans);
}
}
#include <stdio.h>int main() {int n, q, low, high, key, cnt, i;scanf("%d", &n);int likes[n];for (i=0; i<n; ++i)scanf("%d", &likes[i]);scanf("%d", &q);while (q--) {cnt = 0;scanf("%d %d %d", &low, &high, &key);for (i=low-1; i<high; ++i)if (likes[i] == key)cnt++;printf("%d\n", cnt);}return 0;}
#include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; vector<int> users(n); for(int i = 0; i < n; cin >> users[i++]); int q; cin >> q; vector<int> l(q), r(q), k(q); for(int i = 0; i < q; cin >> l[i] >> r[i] >> k[i++]); map<int, vector<int>> mp; for(int i = 0; i < n; ++i) mp[users[i]].push_back(i+1); vector<int> res(q, 0); for(int i = 0; i < q; ++i) { if(mp.count(k[i]) == 0) continue; auto pos = mp[k[i]]; auto low = lower_bound(pos.begin(), pos.end(), l[i]); auto up = upper_bound(pos.begin(), pos.end(), r[i]); res[i] = up - low; } for(int i = 0; i < q; ++i) cout << res[i] << endl; }
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int[] arr = new int[n]; for (int i = 0; i < n; i++) { arr[i] = in.nextInt(); } int q = in.nextInt(); int[][] query = new int[q][3]; for (int i = 0; i < q; i++) { query[i][0] = in.nextInt(); query[i][1] = in.nextInt(); query[i][2] = in.nextInt(); } for (int i = 0; i < q; i++) { int result = 0; int start = query[i][0] - 1; int end = query[i][1] - 1; for(int j = start; j <= end; j++){ if(arr[j] == query[i][2]){ result++; } } System.out.println(result); } } }
#include<bits/stdc++.h> using namespace std; int main(void){ int n; cin>> n; int user[n]; memset(user, 0, n*4); for(int i=0; i<n;i++) cin>> user[i]; int q; cin>> q; int request[q][3]; for(int i=0; i<q;i++){ for(int j=0; j<3;j++) cin>> request[i][j]; } vector<int> res; for(int i=0; i<q;i++){ int left = request[i][0], right=request[i][1], key = request[i][2]; int num=0; for(int j=left-1; j<=right-1 ;j++){ if(user[j] == key){ num++; } } res.push_back(num); } for(auto it: res) cout<< it<<endl; return 0; }左右指针
这道题时间限制不太行啊,我暴力也过了 (1049ms)
#include using namespace std; int n, p; int T[300005]; void solve(int l, int r, int k) { int cnt = 0; for(int i = l; i <= r; ++i) { if(T[i] == k) ++cnt; } printf("%d\n", cnt); } int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%d", &T[i]); scanf("%d",&p); for(int i = 0; i < p; ++i) { int l, r, k; scanf("%d%d%d", &l, &r, &k); solve(l, r, k); } }
再来一个二分的解法,这个不如上面的快(2110ms),应该和测试用例过有关。
#include <iostream> #include <vector> #include <algorithm> #include <cstdio> #include <cstdlib> #include <map> using namespace std; int n, q; int T[300005]; int main() { scanf("%d", &n); for(int i = 0; i < n; ++i) { scanf("%d", &T[i]); } map<int, vector<int>> t; scanf("%d", &q); for(int i = 0; i < q; ++i) { int l, r, k; scanf("%d%d%d", &l, &r, &k); if(t.find(k) == t.end()) { t[k] = vector<int>(); for(int i = 0; i < n; ++i) if(T[i] == k) { t[k].push_back(i+1); // cout << "insert " << i << endl; } } auto low = lower_bound(t[k].begin(), t[k].end(), l); auto up = upper_bound(t[k].begin(), t[k].end(), r); printf("%d\n", up - low); } return 0; }