【codeforces 691 F】【数论+前缀和 好题】【求序列中乘积大于等于p的点对的个数】
2016-11-22 23:20
399 查看
传送门:http://codeforces.com/contest/691/problem/F
题意:求序列中乘积大于等于p的点对的个数
刚开始还想用数据结构维护一下,想想不靠谱
先反向思考求乘积小于p的情况,具体的有两种思路
思路一:类似于埃式筛法,cnt[a[i]]记录a[i]的个数,mul[i]记录点对乘积是i*j的个数
复杂度:O(NloglogN+m)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll __int64
const int N=3e6+10;
int cnt
, a
, p
;
ll mul
;
int main(){
int n, m;
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
cnt[a[i]]++;
}
scanf("%d", &m);
for(int i=1; i<=m; i++)scanf("%d", &p[i]);
for(int i=1; i<N; i++){
if(!cnt[i])continue;
for(int j=i; j<N; j+=i){//用埃式筛法的思想处理乘积问题
mul[j]+=1LL*cnt[i]*(cnt[j/i]-(j/i == i));
/* if(j/i!=i)mul[j]+=1LL*cnt[i]*cnt[j/i];
else mul[j]+=1LL*cnt[i]*(cnt[i]-1); //mul[j]表示乘积为j的个数*/
}
}
for(int i=1; i<N; i++)mul[i]+=mul[i-1];
for(int i=1; i<=m; i++){
ll ans=1LL*n*(n-1)-mul[p[i]-1]; //不要忘记LL
printf("%I64d\n", ans);
}
return 0;
}
思路二:
先去重再离散化,这时候a[i]表示的下标,按下标枚举去重后的数组并且点对的乘积小于p,这样子均摊的复杂度还是O(N)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll __int64
const int N=3e6+10;
int cnt
, a
, b
;
ll mul
;
int main(){
int n, m;
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
b[i]=a[i];
}
scanf("%d", &m);
sort(b+1, b+n+1);
int tol=unique(b+1, b+n+1)-(b+1);//离散化
for(int i=1; i<=n; i++)
a[i]=lower_bound(b+1, b+tol+1, a[i])-b;
for(int i=1; i<=n; i++)cnt[a[i]]++;
ll all=1LL*n*(n-1);
n=tol;
for(int i=1; i<=n; i++){//复杂度大概O(sqrt(n)*sqrt(n))
for(int j=1; j<=n; j++){
if(b[i]*b[j]<N) mul[b[i]*b[j]]+=cnt[i]*(cnt[j]-(i==j));
else break;
}
}
for(int i=1; i<N; i++)mul[i]+=mul[i-1];
while(m--){
int p;
scanf("%d", &p);
printf("%I64d\n", all-mul[p-1]);
}
return 0;
}
F. Couple Cover
time limit per test
3 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output
Couple Cover, a wildly popular luck-based game, is about to begin! Two players must work together to construct a rectangle. A bag with n balls,
each with an integer written on it, is placed on the table. The first player reaches in and grabs a ball randomly (all balls have equal probability of being chosen) — the number written on this ball is the rectangle's width in meters. This ball is not returned
to the bag, and the second player reaches into the bag and grabs another ball — the number written on this ball is the rectangle's height in meters. If the area of the rectangle is greater than or equal some threshold p square
meters, the players win. Otherwise, they lose.
The organizers of the game are trying to select an appropriate value for p so that the probability of a couple winning is not too high
and not too low, but they are slow at counting, so they have hired you to answer some questions for them. You are given a list of the numbers written on the balls, the organizers would like to know how many winning pairs of balls exist for different values
of p. Note that two pairs are different if either the first or the second ball is different between the two in pair, and two different
balls with the same number are considered different.
Input
The input begins with a single positive integer n in its own line (1 ≤ n ≤ 106).
The second line contains n positive integers — the i-th
number in this line is equal to ai (1 ≤ ai ≤ 3·106),
the number written on the i-th ball.
The next line contains an integer m (1 ≤ m ≤ 106),
the number of questions you are being asked.
Then, the following line contains m positive integers — the j-th
number in this line is equal to the value of p(1 ≤ p ≤ 3·106)
in the j-th question you are being asked.
Output
For each question, print the number of winning pairs of balls that exist for the given value of p in the separate line.
Examples
input
output
input
output
题意:求序列中乘积大于等于p的点对的个数
刚开始还想用数据结构维护一下,想想不靠谱
先反向思考求乘积小于p的情况,具体的有两种思路
思路一:类似于埃式筛法,cnt[a[i]]记录a[i]的个数,mul[i]记录点对乘积是i*j的个数
复杂度:O(NloglogN+m)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll __int64
const int N=3e6+10;
int cnt
, a
, p
;
ll mul
;
int main(){
int n, m;
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
cnt[a[i]]++;
}
scanf("%d", &m);
for(int i=1; i<=m; i++)scanf("%d", &p[i]);
for(int i=1; i<N; i++){
if(!cnt[i])continue;
for(int j=i; j<N; j+=i){//用埃式筛法的思想处理乘积问题
mul[j]+=1LL*cnt[i]*(cnt[j/i]-(j/i == i));
/* if(j/i!=i)mul[j]+=1LL*cnt[i]*cnt[j/i];
else mul[j]+=1LL*cnt[i]*(cnt[i]-1); //mul[j]表示乘积为j的个数*/
}
}
for(int i=1; i<N; i++)mul[i]+=mul[i-1];
for(int i=1; i<=m; i++){
ll ans=1LL*n*(n-1)-mul[p[i]-1]; //不要忘记LL
printf("%I64d\n", ans);
}
return 0;
}
思路二:
先去重再离散化,这时候a[i]表示的下标,按下标枚举去重后的数组并且点对的乘积小于p,这样子均摊的复杂度还是O(N)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll __int64
const int N=3e6+10;
int cnt
, a
, b
;
ll mul
;
int main(){
int n, m;
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
b[i]=a[i];
}
scanf("%d", &m);
sort(b+1, b+n+1);
int tol=unique(b+1, b+n+1)-(b+1);//离散化
for(int i=1; i<=n; i++)
a[i]=lower_bound(b+1, b+tol+1, a[i])-b;
for(int i=1; i<=n; i++)cnt[a[i]]++;
ll all=1LL*n*(n-1);
n=tol;
for(int i=1; i<=n; i++){//复杂度大概O(sqrt(n)*sqrt(n))
for(int j=1; j<=n; j++){
if(b[i]*b[j]<N) mul[b[i]*b[j]]+=cnt[i]*(cnt[j]-(i==j));
else break;
}
}
for(int i=1; i<N; i++)mul[i]+=mul[i-1];
while(m--){
int p;
scanf("%d", &p);
printf("%I64d\n", all-mul[p-1]);
}
return 0;
}
F. Couple Cover
time limit per test
3 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output
Couple Cover, a wildly popular luck-based game, is about to begin! Two players must work together to construct a rectangle. A bag with n balls,
each with an integer written on it, is placed on the table. The first player reaches in and grabs a ball randomly (all balls have equal probability of being chosen) — the number written on this ball is the rectangle's width in meters. This ball is not returned
to the bag, and the second player reaches into the bag and grabs another ball — the number written on this ball is the rectangle's height in meters. If the area of the rectangle is greater than or equal some threshold p square
meters, the players win. Otherwise, they lose.
The organizers of the game are trying to select an appropriate value for p so that the probability of a couple winning is not too high
and not too low, but they are slow at counting, so they have hired you to answer some questions for them. You are given a list of the numbers written on the balls, the organizers would like to know how many winning pairs of balls exist for different values
of p. Note that two pairs are different if either the first or the second ball is different between the two in pair, and two different
balls with the same number are considered different.
Input
The input begins with a single positive integer n in its own line (1 ≤ n ≤ 106).
The second line contains n positive integers — the i-th
number in this line is equal to ai (1 ≤ ai ≤ 3·106),
the number written on the i-th ball.
The next line contains an integer m (1 ≤ m ≤ 106),
the number of questions you are being asked.
Then, the following line contains m positive integers — the j-th
number in this line is equal to the value of p(1 ≤ p ≤ 3·106)
in the j-th question you are being asked.
Output
For each question, print the number of winning pairs of balls that exist for the given value of p in the separate line.
Examples
input
5 4 2 6 1 3 4 1 3 5 8
output
20 18 14 10
input
2 5 6 2 30 31
output
2 0
相关文章推荐
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- 【cf 487C】【数论+构造】【根据前缀积取模构造序列】
- 【codeforces 691 E】【矩阵快速幂 思维题】【给定序列,从序列中选择k个数(可以重复选择),使得得到的排列满足xi与xi+1异或的二进制表示中1的个数是3的倍数。问满足条件的序列个数】
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- 子序列和等于k__前缀和+hash
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- CodeForces - 416A (判断大于小于等于 模拟题)
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- 【codeforces 727 C】【交互题 求原数组】【告诉你有一个长度为n序列,你可以问n个问题,每个问题为ai+aj等于多少,最后输出这个序列】
- 每天一道LeetCode-----寻找地增序列中第一个大于等于目标元素的位置
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- CodeForces - 416A (判断大于小于等于 模拟题)
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和
- 【数论】 求小于等于 N 的与N互质的所有数的乘积mod N
- seventh又来出题了 子区间的和大于等于0 逆序对+前缀和