[Nowcoder]2020牛客寒假算法基础集训营2

20200206 第二场

进度(7 / 10) 未完成:H / I / J

 

A、做游戏

1、链接

https://ac.nowcoder.com/acm/contest/3003/A

2、题面

牛牛和 牛可乐在玩石头剪刀布。

众所周知,石头剪刀布的规则是这样的:

- 在一局游戏中,双方各自出石头、剪刀、布其一。
- 胜负关系如下:
[Nowcoder]2020牛客寒假算法基础集训营2_第1张图片

牛牛和 牛可乐进行了多轮游戏, 牛牛总共出了 A 次石头,B 次剪刀,C 次布;牛可乐总共出了 X 次石头,Y 次剪刀,Z 次布。 你需要求出牛牛最多获胜多少局。

3、思路

小型贪心。牛牛出石头时牛可乐优先出剪刀,同理剪刀-布,布-石头。三次比较均取两者较小值,剩下的便是不可能获胜的局了。

4、代码

 1 #include  
 2 using namespace std;
 3 
 4 long long a, b, c, d, e, f;
 5 
 6 int main() {
 7     cin >> a >> b >> c >> d >> e >> f;
 8     cout << min(a, e) + min(b, f) + min(c, d);
 9     return 0;
10 }

 

B、排数字

1、链接

https://ac.nowcoder.com/acm/contest/3003/B

2、题面

牛可乐 最喜爱的字符串是 616。 

牛可乐得到了一个纯数字的字符串 S,他想知道在可以任意打乱 S 顺序的情况下,最多有多少个不同的子串为 616。 
 
当两个子串  S[l1…r1],S[l2…r2] 满足 l1≠l2 或 r1≠r2 时它们被认为是不同的。

3、思路

签到题。将字符串中1和6提取出来,以616161...的形式排列为最优解,则统计1和6的个数并处理一下即可得到答案。

4、代码

 1 #include  
 2 using namespace std;
 3 
 4 #define MAXN 200005
 5 
 6 int n, a, b;
 7 char s[MAXN];
 8 
 9 int main() {
10     cin >> n >> s;
11     for (int i = 0; i < n; i++) a += s[i] == '1', b += s[i] == '6';
12     cout << min(a, b - 1);
13     return 0;
14 }

 

C、算概率

1、链接

https://ac.nowcoder.com/acm/contest/3003/C

2、题面

牛牛刚刚考完了期末,尽管 牛牛 做答了所有 n 道题目,但他不知道有多少题是正确的。
不过,牛牛 知道第 ii 道题的正确率是 pipi
牛牛 想知道这 n 题里恰好有 0,1,…,n0,1,,n 题正确的概率分别是多少,对 109+710^9+7 取模。
对 109+710^9+7 取模的含义是:对于一个 b≠0b !=0 的不可约分数 aba/b,存在 qq 使得 b×q mod (109+7)=ab * q mod (10^9+7) =aqq 即为 aba / b 对 109+710^9+7 取模的结果。

3、思路

自己瞎捣鼓了许久没做出来。看了下题解,发现我duck不必纠结于将pi化成分数形式。

这也算是一道DP题。设f[i][j]表示前i道题里j道题正确的概率,状态转移:f[i][j] = f[i - 1][j - 1] * p[i] + f[i - 1][j] * p_[i],其中p_[i]表示做错的概率。

根据题意,p_[i] = mod + 1 - p[i],上述数据全部需要取模。

4、代码

 1 #include  
 2 using namespace std;
 3 
 4 typedef long long ll;
 5 
 6 #define MAXN 2005
 7 #define MOD 1000000007
 8 
 9 ll n, a[MAXN], b[MAXN], f[MAXN][MAXN];
10 
11 int main() {
12     cin >> n;
13     for (int i = 1; i <= n; i++)
14         cin >> a[i], b[i] = (MOD + 1 - a[i]) % MOD; 
15     f[0][0] = 1; 
16     for (int i = 1; i <= n; i++) {
17         f[i][0] = (f[i - 1][0] * b[i]) % MOD;
18         for (int j = 1; j <= i; j++)
19             f[i][j] = ((f[i - 1][j] * b[i]) % MOD + (f[i - 1][j - 1] * a[i]) % MOD) % MOD;
20     }
21     for (int i = 0; i <= n; i++) cout << f[n][i] << ' ';
22     return 0;
23 }

 

D、数三角

1、链接

https://ac.nowcoder.com/acm/contest/3003/D

2、题面

牛牛得到了一个平面,这个平面上有 n 个不重合的点,第 i 个点的坐标为 (xi,yi)

牛牛想知道,这 n 个点形成的三角形中,总共有多少个钝角三角形。

3、思路

平面几何题。枚举任意两个点,再选择第三个点,看是否满足钝角三角形的条件。设当前选择的两个点为A, B,如图所示,

[Nowcoder]2020牛客寒假算法基础集训营2_第2张图片

根据几何知识,当且仅当第三个点位于如下两种位置,可以与A, B组成钝角三角形:

①以AB中点为圆心的圆内;

②不在与AB所连的线段垂直且分别过A, B的两条直线之间(排除①的圆内)。

文字描述显得比较拗口,但图示就比较清晰了。那么:

对于①,求得中点和半径,判定第三个点和圆心距离是否小于半径即可;

对于②,求得直线AB的斜率,进而求得与之垂直的直线的斜率k,分别将A, B, 所求的第三个点代入求得所在直线的截距b,如果第三个点的b小于A的或者大于B的,即满足条件。

平面几何题一个常见的要考虑的问题就是斜率为0或者斜率为无穷大的情况,需要特殊考虑。

 

4、代码

 1 #include  
 2 using namespace std;
 3 
 4 #define MAXN 200005
 5 
 6 int n, ans;
 7 double x[MAXN], y[MAXN];
 8 
 9 double dis(int a, int b) {
10     return sqrt((y[a] - y[b]) * (y[a] - y[b]) + (x[a] - x[b]) * (x[a] - x[b]));
11 }
12 
13 int main() {
14     cin >> n;
15     for (int i = 1; i <= n; i++) cin >> x[i] >> y[i];
16     for (int i = 1; i <= n - 2; i++)
17         for (int j = i + 1; j <= n - 1; j++) {                
18                 x[0] = (x[j] + x[i]) / 2.0, y[0] = (y[j] + y[i]) / 2.0;
19                 double r = dis(i, 0);
20                 for (int l = j + 1; l <= n; l++) {
21                     if (y[j] == y[i])
22                         ans += (x[l] < min(x[i], x[j]) || x[l] > max(x[i], x[j])) && y[l] != y[i];
23                     else if (x[j] == x[i])
24                         ans += (y[l] < min(y[i], y[j]) || y[l] > max(y[i], y[j])) && x[l] != x[i];
25                     else {
26                         double k = -1 / ((y[j] - y[i]) / (x[j] - x[i]));
27                         double bi = y[i] - k * x[i], bj = y[j] - k * x[j]; 
28                         if (-1 / ((y[l] - y[i]) / (x[l] - x[i])) == k) continue; 
29                         double bl = y[l] - k * x[l];
30                         ans += bl < min(bi, bj) || max(bi, bj) < bl;
31                     }
32                     ans += dis(l, 0) < r;
33                 }
34         }
35     cout << ans;
36     return 0;
37 }

 

E、做计数

1、链接

https://ac.nowcoder.com/acm/contest/3003/E

2、题面

这一天,牛牛与 牛魔王相遇了――然而这并不在 牛牛期望之中。
 牛魔王不出意料又给 牛牛一道看似很难的题目:求有多少个不同的正整数三元组 (i,j,k) 满足 i×j≤n

牛牛并不会做,你能略施援手吗?
当两个三元组  (i1,j1,k1),(i2,j2,k2) 满足 i1≠i2 或 j1≠j2 或 k1≠k2 时它们被认为是不同的。

3、思路

看到根号第一反应是平方。数学符号太难打了,直接复制别人的题解好了。

[Nowcoder]2020牛客寒假算法基础集训营2_第3张图片

然后我就一个个i去枚举,,果不其然就T了。想了许久也没找到个好办法,看了题解给的code:

枚举小于n的完全平方数x,再枚举x的因子,仅需在sqrt(x)范围内枚举,由于(i, j)和(j, i)不等价,再在结果上*2即可,当然(i, i)需要特殊考虑。

4、代码

 1 #include 
 2 using namespace std;
 3 
 4 int n, ans;
 5 
 6 int main() {
 7     cin >> n;
 8     for (int i = 1; i <= sqrt(n); i++) {
 9         int o = i * i;
10         for (int j = 1; j <= sqrt(o); j++)
11             ans += i == j ? 1 : o % j == 0 ? 2 : 0;
12     }
13     cout << ans;
14     return 0;
15 }

 

F、拿物品

1、链接

https://ac.nowcoder.com/acm/contest/3003/F

2、题面

牛牛和 牛可乐 面前有 n 个物品,这些物品编号为 1,2,…,nn ,每个物品有两个属性 ai,bi 。


牛牛与 牛可乐会轮流从剩下物品中任意拿走一个, 牛牛先选取。

设 牛牛选取的物品编号集合为 H,牛可乐选取的物品编号的集合为 T,取完之后,牛牛 得分为 ∑i∈Hai;而 牛可乐得分为 ∑i∈Tbi

牛牛和 牛可乐都希望自己的得分尽量比对方大(即最大化自己与对方得分的差)。

你需要求出两人都使用最优策略的情况下,最终分别会选择哪些物品,若有多种答案或输出顺序,输出任意一种。

3、思路

贪心。这题思路不错,值得细品的一种贪心。

由于目的是使得分差最大,对于物品i,A得ai,B得bi,如果A拿了,相当于A得了分,而B同时没得到分,则相当于分差拉开了ai +bi。

根据这个贪心思路,我们将物品按照ai + bi从大到小的顺序排序,然后两人依次拿即可。

4、代码

 1 #include 
 2 using namespace std;
 3 
 4 #define MAXN 200005
 5 
 6 int n, ans[2][MAXN], o = 1;
 7 
 8 struct item {
 9     int p[3], o;
10 } a[MAXN];
11 
12 struct cmp {
13     bool operator () (item a, item b) {
14         return a.p[2] > b.p[2];
15     }
16 } x;
17 
18 int main() {
19     cin >> n;
20     for (int j = 0; j <= 1; j++) 
21         for (int i = 1; i <= n; i++) cin >> a[i].p[j], a[i].o = i;
22     for (int i = 1; i <= n; i++) a[i].p[2] = a[i].p[0] + a[i].p[1];
23     sort(a + 1, a + n + 1, x);
24     for (int i = 1; i <= n; i++) o ^= 1, ans[o][(i - 1) / 2 + 1] = a[i].o;
25     for (int i = 1; i <= n - n / 2; i++) cout << ans[0][i] << ' ';
26     cout << endl;
27     for (int i = 1; i <= n / 2; i++) cout << ans[1][i] << ' ';
28     return 0;
29 }

 

G、判正误

1、链接

https://ac.nowcoder.com/acm/contest/3003/G

2、题面

牛可乐有七个整数 a,b,c,d,e,f,g 并且他猜想 a^d+b^e+c^f=g。但牛可乐无法进行如此庞大的计算。
请验证牛可乐的猜想是否成立。

3、思路

这么憨批的签到题我还去推式子。。想着应该没这么简单。

然后写个快速幂又被卡常@!%@#¥#

可以直接用pow,可以写快速幂,快速幂模数设成1e9+7可过,列一下常用模数方便以后用:

12255871, 16341163, 21788233, 29050993, 38734667, 51646229, 68861641,  91815541, 1000000007, 1000000009

4、代码

 1 #include  
 2 using namespace std;
 3 
 4 typedef long long ll;
 5 #define MOD 1000000007
 6 
 7 ll t, a, b, c, d, e, f, g;
 8 
 9 ll qpow(ll x, ll y) {
10     ll o = x, res = 1;
11     while (y) {
12         if (y & 1) (res *= o) %= MOD;
13         (o *= o) %= MOD, y >>= 1;
14     }
15     return res;
16 }
17 
18 int main() {
19     cin >> t;
20     for (int i = 1; i <= t; i++) {
21         cin >> a >> b >> c >> d >> e >> f >> g;
22         printf(qpow(a, d) + qpow(b, e) + qpow(c, f) == g ? "Yes\n" : "No\n");
23     }
24     return 0;
25 }

你可能感兴趣的:([Nowcoder]2020牛客寒假算法基础集训营2)