[hdu5101]计数问题

http://acm.hdu.edu.cn/showproblem.php?pid=5101

题目大意:给n个集合,求从两个不同集合里面各取一个数使得它们的和大于给定数的方案数。

ans=从所有数里面取两个数的方案数-从每个集合里面取两个数的方案数(这是关键)


如果不转换也可以这么做,离散一下,然后树状数组统计也行,具体见代码。

代码一:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 #include <map>
 7 #include <vector>
 8 #include <stack>
 9 #include <string>
10 #include <ctime>
11 #include <queue>
12 #define mem0(a) memset(a, 0, sizeof(a))
13 #define mem(a, b) memset(a, b, sizeof(a))
14 #define lson l, m, rt << 1
15 #define rson m + 1, r, rt << 1 | 1
16 #define eps 0.0000001
17 #define lowbit(x) ((x) & -(x))
18 #define memc(a, b) memcpy(a, b, sizeof(b))
19 #define x_x(a) ((a) * (a))
20 #define LL long long
21 #define DB double
22 #define pi 3.14159265359
23 #define MD 10000007
24 #define INF (int)1e9
25 #define max(a, b) ((a) > (b)? (a) : (b))
26 using namespace std;
27 int b[110000];
28 LL solve(int a[], int n, int x)
29 {
30         LL ans = 0;
31         for(int i = 1; i <= n; i++) {
32                 int tmp = upper_bound(a + 1, a + 1 + n, x - a[i]) - a;
33                 ans += n - tmp + 1;
34         }
35         return ans;
36 }
37 int main()
38 {
39         //freopen("input.txt", "r", stdin);
40         //freopen("output.txt", "w", stdout);
41         int n, k, T;
42         cin>> T;
43         while(T--) {
44                 cin>> n>> k;
45                 LL ans1 = 0, ans2 = 0;
46                 int tot = 0;
47                 for(int i = 1; i <= n; i++) {
48                         int m, a[110];
49                         cin>> m;
50                         for(int j = 1; j <= m; j++) {
51                                 scanf("%d", &a[j]);
52                                 b[++tot] = a[j];
53                         }
54                         sort(a + 1, a + 1 + m);
55                         ans1 += solve(a, m, k);
56                 }
57                 sort(b + 1, b + 1 + tot);
58                 ans2 = solve(b, tot, k);
59                 cout<< (ans2 - ans1) / 2<< endl;
60         }
61         return 0;
62 }
View Code

代码二(树状数组):

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <map>
  7 #include <vector>
  8 #include <stack>
  9 #include <string>
 10 #include <ctime>
 11 #include <queue>
 12 #define mem0(a) memset(a, 0, sizeof(a))
 13 #define mem(a, b) memset(a, b, sizeof(a))
 14 #define lson l, m, rt << 1
 15 #define rson m + 1, r, rt << 1 | 1
 16 #define eps 0.0000001
 17 #define lowbit(x) ((x) & -(x))
 18 #define memc(a, b) memcpy(a, b, sizeof(b))
 19 #define x_x(a) ((a) * (a))
 20 #define LL long long
 21 #define DB double
 22 #define pi 3.14159265359
 23 #define MD 10000007
 24 #define INF (int)1e9
 25 #define max(a, b) ((a) > (b)? (a) : (b))
 26 using namespace std;
 27 map<int, int> hash;
 28 int nn, tot, arr[220000], arr0[220000], c[220000], a[1200][120], m[1200];
 29 void init()
 30 {
 31         sort(arr + 1, arr + 1 + tot);
 32         arr0[1] = arr[1];
 33         nn = 1;
 34         hash[arr0[1]] = 1;
 35         for(int i = 2; i <= tot; i++) {
 36                 if(arr[i] != arr[i - 1]) {
 37                         arr0[++nn] = arr[i];
 38                         hash[arr[i]] = nn;
 39                 }
 40         }
 41 }
 42 void update(int p, int x)
 43 {
 44         while(p <= nn) {
 45                 c[p] += x;
 46                 p += lowbit(p);
 47         }
 48 }
 49 void insert(int a[], int n)
 50 {
 51         for(int i = 1; i <= n; i++) {
 52                 int tmp = hash[a[i]];
 53                 update(tmp, 1);
 54         }
 55 }
 56 int sum(int p)
 57 {
 58         int ans = 0;
 59         while(p) {
 60                 ans += c[p];
 61                 p -= lowbit(p);
 62         }
 63         return ans;
 64 }
 65 int query(int L, int R)
 66 {
 67         return sum(R) - sum(L - 1);
 68 }
 69 int find(int x)
 70 {
 71         int l = 1, r = nn;
 72         while(l < r) {
 73                 int m = (l + r) >> 1;
 74                 if(arr0[m] > x) r = m;
 75                 else l = m + 1;
 76         }
 77         return l;
 78 }
 79 int main()
 80 {
 81         //freopen("input.txt", "r", stdin);
 82         //freopen("output.txt", "w", stdout);
 83         int T;
 84         cin>> T;
 85         while(T--) {
 86                 hash.clear();
 87                 mem0(c);
 88                 int n, k;
 89                 cin>> n>> k;
 90                 tot = 0;
 91                 for(int i = 1; i <= n; i++) {
 92                         cin>> m[i];
 93                         for(int j = 1; j <= m[i]; j++) {
 94                                 scanf("%d", &a[i][j]);
 95                                 arr[++tot] = a[i][j];
 96                         }
 97                 }
 98                 init();
 99                 insert(a[1], m[1]);
100                 LL ans = 0;
101                 for(int i = 2; i <= n; i++) {
102                         for(int j = 1; j <= m[i]; j++) {
103                                 int tmp = find(k - a[i][j]);
104                                 ans += query(tmp, nn);
105                         }
106                         insert(a[i], m[i]);
107                 }
108                 cout<< ans<< endl;
109         }
110         return 0;
111 }
View Code

 

转载于:https://www.cnblogs.com/jklongint/p/4095157.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值