问一下A题的思路,希望说的详细点
- 添加评论
问一下A题的思路,希望说的详细点
ans居然要为long long 才能A。。
第四题,考虑那些点可以作为圆心,首先每个敌人的点是不行的,第二,2个点的中心也是不可以的,然后就考虑到: 以每个敌人的点做圆,然后统计平面上那些点覆盖的圆最多,这个问题好像有点复杂,说实话,想到这,我也不会解(我只会解线段覆盖最多的点),然后当然是百度和谷歌了,很容易出现一个题目叫单位圆覆盖最多的点,poj1981, 这不就是我们想要的么, 那就把单位圆搞成上面的半径, 这样就直接ac了,当然,应该算抄袭吧。哈哈!
其实我都忘记搞范围了,上网搞了个poj1981的代码,然后把半径改成输入的r,就直接交了,谁知道就直接a了。其实我是不会做的, -w-
找到一个解释 https://www.quora.com/What-is-an-algorithm-for-enclosing-the-maximum-number-of-points-in-a-2-D-plane-with-a-fixed-radius-circle
第三道题目,分析一下,因为肯定能构成一棵树,不知道去掉那一行,考虑树的父节点只有一个,所以可能的情况,就是一个点有2个父节点,所以结果就是这个点的出现行,注意特例:正常情况下,根节点没有出现,如果出现,结果肯定只有这一行,然后就可以了。
第二题的话,就是简单的dp,因为每个题有做对和做错2种,然后每一次更新一下做对i道题目的概率,就可以了,这个应该算最简单得了吧。
//我简单写一下吧,代码可能有点丑,希望对你有所帮助。
#include<bits/stdc++.h>
#define pb push_back
typedef long long ll;
using namespace std;
typedef pair<int, int> pii;
const int maxn = 1e3 + 10;
int a[maxn];
map<int, int> ma;
int cnt;
int n;
map<int, int> mc;
void solve() {
cin >> n;
if(n < 4) {
cout << 0 << endl;
return;
}
for (int i = 0; i < n; i++) {
cin >> a[i];
//统计每个数出现的次数
mc[a[i] ]++;
}
//map<int, int> ma;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
//统计可能的和的个数
ma[a[i] + a[j] ]++;
}
}
ll res = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
// 枚举小hi可以拿的情况
if(a[i] != a[j])
//计算小ho可以的情况
//就像楼上说的
res += ma[a[i] + a[j] ] - mc[a[i] ] * mc[a[j]] + (mc[a[i] ] -1) *( mc[a[j]] - 1);
else {
//相等的时候需要特别考虑
int t = mc[a[i] ];
int td = t;
t -= 2;
res += ma[a[i] + a[j] ] - td * (td - 1) / 2 + t * (t - 1) / 2;
}
//cout << ma[a[i] + a[j] ] << " " << mc[a[i] ] * mc[a[j]] << " " << (mc[a[i] ] -1) *( mc[a[j]] - 1) << endl;
//cout << i << " " << j << " " << res << endl;
}
}
cout << res << endl;
}
int main() {
//freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
solve();
return 0;
}
假设分配给小hi的金币为 a[i]
和a[j]
,现在的问题是求剩下的元素中有多少组 p, q
使得 a[i] + a[j] = a[p] + a[q]
。如果暴力枚举所有可能的 p, q
,需要 O(n^2)
时间,再加上枚举i, j
的时间,时间复杂度是 O(n^4)
,会超时。所以不能枚举 p, q
。
把输入保存在数组 a[]
中。
令 sumCnt[x]
表示两袋金币之和 a[i] + a[j] = x
组合数。
令 cnt[y]
表示元素 y
出现的次数。
假设分配给小hi的金币为 x = a[i] + a[j]
,那么x
一共有 sumCnt[x]
种可能的组合。
令 c1 = cnt[a[i]], c2 = cnt[a[j]]
,
假设 a[i] != a[j]
。
去掉a[i], a[j]
之前,a[i]
和a[j]
一共可以组成 c1 * c2
个 x
。去掉 a[i]
后,还有 c1 - 1
个与 a[i]
相同的元素,去掉 a[j]
后,还有 c2 - 1
个与 a[j]
相同的元素,它们还可以组成 (c1 - 1) * (c2 - 1)
个 x
。
所以,如果分配给小hi的金币为 a[i]
和a[j]
,那么存在 sumCnt - (c1 * c2 - (c1 - 1) * (c2 - 1))
对 p, q
使得 a[i] + a[j] = a[p] + a[q]
。
当 a[i] == a[j]
时,也是类似的处理。
现在,求p, q
的组数只需要 O(1)
,总的时间复杂度是 O(n^2)
。
import java.util.* ;
public class Main {
public static double solution(int n, int m, double[]a) {
double[][]dp = new double[n + 1][m + 1];
dp[0][0] = 1.0; //抛0次出现0次正概率为1,为必然事件
double temp1 = 1.0;
double temp2 = 1.0;
for (int i = 1; i <= m; i++) {
temp1 *= a[i - 1];
temp2 *= (1 - a[i - 1]);
dp[i][i] = temp1; //硬币全为正时概率为前i个数连乘
dp[i][0] = temp2; //硬币全为反时概率为1-前i个数的结果连乘
}
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= i && j <= m; j++) {
dp[i][j] = dp[i - 1][j] * (1 - a[i - 1]) + dp[i - 1][j - 1] * a[i - 1]; //抛i次恰好出现j次正的概率=抛i-1次出现j次正的概率乘以第i次为反的概率+抛i-1次出现j-1次正的概率乘以第i次为正的概率
}
}
return dp[n][m];
}
public static void main(String[]args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
int m = sc.nextInt();
double[]a = new double[n];
for (int i = 0; i < n; i++)
a[i] = sc.nextDouble();
System.out.println(solution(n, m, a));
}
}
}
看错了
尴尬,A题给一下吧
题目中点数貌似是2000个,你开的数组是300。。。居然A了