牛客练习赛41

链接:https://ac.nowcoder.com/acm/contest/373/A
来源:牛客网

翻硬币问题
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

Alice和Bob正在玩一个很经典的游戏。
 n n个硬币初始时全部正面朝上,每一轮Alice必须选择其中任意的恰好 m m枚硬币并将它们全部翻转,如果若干轮翻转后所有硬币全部反面朝上,那么Alice就赢得了游戏。
假设我们认为每枚硬币只有正面朝上和反面朝上两种状态且只考虑  m m为偶数的情况,问题会比较简单。
但是出题人希望这道题更毒瘤一些,所以他增加了一条规则:Bob在整个游戏中可以有一次机会使坏--在Alice某一轮 翻转完之后,偷偷选择任意 硬币并将它翻转。
为了不让Alice赢得游戏,Bob会采取最优的策略。
现在给定  n n和 m m,请问Alice是否可以赢得游戏?
注意:
  1. Bob虽然可以在任何轮翻转之后使坏,但是在整个游戏中只有一次这样的机会。也就是说,如果在某一轮之后使用了这个机会,那么以后都不能再使用。
  2. 轮次可以认为是无限的,只要在任何一轮翻转后所有硬币全部反面朝上,Alice就立即赢得游戏胜利,Bob即使没有用掉使坏的机会也不能再偷偷翻转硬币。

输入描述:

每个输入文件有多个测试样例。
第一行一个整数  T(T30000) T(T≤30000)--测试样例个数。
然后  T T行,每行两个整数 n n和 m m (1mn109,m) (1≤m≤n≤109,m是偶数)--硬币的数量和每一轮翻转硬币的数量。其中第 i+1 i+1行表示第 i i个样例。

输出描述:

输出  T T行,第 i i行输出第 i i个测试样例的答案。
如果Alice可以赢得游戏输出“Yes”,否则输出“No”,请注意区分大小写。
示例1

输入

复制
2
2 2
8 6

输出

复制
Yes
No

说明

对于第一个样例,Alice直接一轮翻转全部两个硬币就可以赢得游戏。

对于第二个样例,Bob如果在第一轮结束后将任意一枚反面朝上的硬币翻转,之后Alice无论怎样翻转硬币也永远不能使得所有硬币全部反面朝上。


题解:
因为m是一个偶数,不妨分类讨论:
1.一回合可以直接翻转所有硬币(n=m)
很显然,答案Yes
2.一回合不能直接翻转所有硬币,因为m是偶数,所以只需要讨论n的奇偶性。
(1)n是奇数
某回合结束后所有硬币反面朝上可以等价于所有硬币都被翻转了奇数次。假设可以达成,那么
该回合后所有回合总翻转次数一定要为奇数(因为奇数个奇数相加是奇数)
然而m是偶数,即使在不使坏的情况下,无论翻转多少个回合,总翻转次数也一定是偶数,
所以在这种情况下是不可能赢得游戏的.答案是No
(2)n是偶数
同理,完成时所有硬币都一定要被翻转了奇数次,但是n是偶数,所以总翻转次数一定要为偶
数,在不被使坏的情况下,至少有可能完成,但是除去n=m的情况外,只要在第一回合后立即
被使坏,不管翻转哪一个硬币,都会使得总翻转次数由总是偶数变成总是奇数,和n为奇数
时原理相同,也不可能赢得游戏,答案是No
结论: n=m时答案是Yes,否则答案是No
 1 #include <iostream>
 2 using namespace std;
 3 
 4 int t;
 5 int main(){
 6     cin >> t;
 7     while(t--){
 8         int n, m;
 9         cin >> n >> m;
10         if(n == m){
11             cout << "Yes" <<endl;
12             continue;
13         }
14          cout << "No" << endl;
15     }
16     return 0;
17 }

链接:https://ac.nowcoder.com/acm/contest/373/C
来源:牛客网

抓捕盗窃犯
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

Q市发生了一起特大盗窃案。这起盗窃案是由多名盗窃犯联合实施的,你要做的就是尽可能多的抓捕盗窃犯。
已知盗窃犯分布于  N N个地点,以及第 i i个地点初始有 ai ai名盗窃犯。
特别的是,对于每一个地点 u u,都有一个固定的地点 v v--当前如果某个盗窃犯位于地点 u u,在下一个时刻他会移动到地点 v v。
你需要通过初始时在某些点设置哨卡来捉住他们。
现在你可以在 M M个地点设置哨卡,如果在某个地点设置哨卡,你可以抓获在任一时刻经过该地点的盗窃犯。
也就是说,哨卡存在的时间是无限长,但哨卡不能移动。

输入描述:

第一行两个整数 N,M(1N,M105) N,M(1≤N,M≤105)。
第二行 N N个整数 a1a2...aN a1a2...aN (0a1,a2,...aN105) (0≤a1,a2,...aN≤105),表示第 i i个地点初始有 ai ai名盗窃犯。
第三行 N N个整数 v1v2...vN v1v2...vN (1v1,v2,...vNN) (1≤v1,v2,...vN≤N),表示当前处于地点 i i的盗窃犯下一个时刻会移动到地点 vi vi。

输出描述:

输出一行一个整数--能够抓捕到的最大数量。
示例1

输入

复制
8 2
1 2 3 4 1 2 3 12
2 3 3 3 6 7 5 8

输出

复制
22

说明

对于样例一,一种可行的方案是:

在地点3、地点8分别设置一个哨卡,此时答案为1+2+3+4+12=22
示例2

输入

复制
8 2
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8 8

输出

复制
36

说明

对于样例二,一种可行的方案是:

在地点2、地点8分别设置一个哨卡,此时答案为1+2+3+4+5+6+7+8=36

题解:

把每个地点看作一个点,那么每个点一定有且仅有一条有向出边。
每个点出度只有1,如果某些点组成了一个有向环,这个环上所有点不会有额外的出边,即这个环一定是一个简单环。
也易证每个点最终都会走向一个环。
结论:单独看待每个联通块,每个连通块一定有且只有一个环,只要在这个环上任何一个点建立哨卡,就能抓到这个联通块中的所有。可以使用把边都看成无向,使用并查集等找出所有连通块并求每个连通块上所有点的数量之和,从大到小排序,取前m大即可。
复杂度O(nlogn)

 1 #include <bits/stdc++.h>
 2 #define ll long long int
 3 #define N 100005
 4 using namespace std;
 5 ll n, m;
 6 ll an[N], bn[N], self[N], fa[N];
 7 ll istrue[N];
 8 vector<ll> vt[N];
 9 
10 void dfs(ll x){
11     self[x] = 1;
12     if(istrue[x] == 1 || vt[x].size() == 0){
13         self[x] = 0;
14         return;
15     }
16     // cout<<x<<endl;
17     for(int i = 0; i < vt[x].size(); i++){
18         ll xn = vt[x][i];
19         if(self[xn] == 1){
20             continue;
21         }
22         dfs(xn);
23         an[x] += an[xn];
24         // cout << x <<" "<<xn <<" "<<i<<endl;
25         istrue[xn] = 1;
26     }
27     vt[x].clear();
28     self[x] = 0;
29 }
30 
31 
32 int main(){
33     cin >> n >> m;
34     for(int i = 1; i <= n; i++)
35         cin >> an[i];
36     for(int i = 1; i <= n; i++){
37         cin >> bn[i];
38         if(bn[i] != i)
39             vt[bn[i]].push_back(i);
40     }
41     memset(istrue, 0, sizeof(istrue));
42     for(int i = 1; i <= n; i++)
43         dfs(i);
44     ll ans = 0;
45     for(int i = 1; i <= n; i++){
46         if(istrue[i] == 0){
47             fa[ans++] = an[i];
48         }
49     }
50     sort(fa, fa + ans);
51     ll cnt = 0;
52     for(int i = ans - 1; i >= 0 && m > 0; i--){
53         cnt += fa[i];
54         m --;
55     }
56     cout << cnt << endl;
57     return 0;
58 }

链接:https://ac.nowcoder.com/acm/contest/373/E
来源:牛客网

球的体积并
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
Special Judge, 64bit IO Format: %lld

题目描述

某天lililalala正在玩一种奇妙的吃鸡游戏--因为在这个游戏里会同时有两个圆形安全区(他们可能相交)。
lililalala觉得求圆的面积并太简单了,所以想把这个问题升级一下。
现在在三维空间里有 2 个球形安全区,分别用四元组  <x1,y1,z1,r1> <x1,y1,z1,r1> 和 <x2,y2,z2,r2> <x2,y2,z2,r2>表示,其中  r1r2 r1、r2表示球半径, (x1,y1,z1) (x1,y1,z1)和 (x2,y2,z2) (x2,y2,z2)表示球心
lililalala想知道安全区的总体积是多少?即求这两个球的体积并。

输入描述:

输入有两行。
第一行四个实数  x1,y1,z1,r1 x1,y1,z1,r1--第一个球的球心坐标和半径。
第二行四个实数  x2,y2,z2,r2 x2,y2,z2,r2--第二个球的球心坐标和半径。
保证所有输入的坐标和半径的范围都在  [100,100] [−100,100] 内。

输出描述:

输出一行一个实数--表示两个球的体积并,你的答案被认为正确,当且仅当绝对误差不超过 106 10−6。
示例1

输入

复制
0 0 0 1
2 0 0 1

输出

复制
8.3775804
示例2

输入

复制
0 0 0 1
0 0 0 0.5

输出

复制
4.1887902


题解:
设两个球  A A和 B B的体积分别为  Va Va和 Vb Vb,半径分别为 ra ra和 rb rb,两球球心距离为 d d。
分三种情况讨论: 两球/相离/外切,那么答案是  Va+Vb Va+Vb;
两球内含/内切时,答案是  max(Va,Vb) max(Va,Vb);
两球相交时,我们可以认为相交部分就是两个球被平面所截的部分,我们称之为球冠。
对于球冠体积有公式: V=πh(3a2+h2)6=πh2(3rh)3V=πh(3a2+h2)6=πh2(3r−h)3 ;
其中  A A为球半径, a a为截面圆半径, h h为垂直于截面的一条直径,即球冠的高 ;
那么  A A对应的球冠参数为: r=ra r=ra , h=rara2rb2+d22dh=ra−ra2−rb2+d22d ;
 B B对应的球冠参数为: r=rb r=rb, h=rbrb2ra2+d22d h=rb−rb2−ra2+d22d ;
代入球冠体积公式便可得到答案。



 1 #include<bits/stdc++.h>
 2 #define mst(a,b) memset(a,b,sizeof(a))
 3 #define ALL(x) x.begin(),x.end()
 4 #define pii pair<int,int>
 5 #define mp make_pair
 6 #define lowbit(x) (x&(-x))
 7 #define X first
 8 #define Y second
 9 using namespace std;
10 typedef long long ll;
11 typedef long long LL;
12 typedef unsigned long long ull;
13 typedef unsigned int ui;
14 typedef pair<ll, ll> pll;
15 const int inf = 0x3f3f3f3f;
16 const ll INF = 0x3f3f3f3f3f3f3f3f;
17 const long double eps = 1e-8;
18 const long double pi = acos(-1.0);
19 const int N = 1e6 + 5;
20 const int mod = 1e8 + 7;
21 const int maxn = 1e7 + 5;
22 struct Point {
23     long double x, y, z, r;
24 } a, b;
25 long double sqr(long double x) {
26     return x * x;
27 }
28 long double dis(Point p, Point q) {
29     return sqrtl(sqr(p.x - q.x) + sqr(p.y - q.y) + sqr(p.z - q.z));
30 }
31 int main() {
32     ios::sync_with_stdio(0);
33     cin.tie(0);
34     cout.tie(0);
35     cin >> a.x >> a.y >> a.z >> a.r;
36     cin >> b.x >> b.y >> b.z >> b.r;
37     if(a.r > b.r)swap(a, b);
38     long double ans = 4. / 3 * pi * (powl(a.r, 3) + powl(b.r, 3));
39     long double d = dis(a, b);
40     if(d >= a.r + b.r) {
41   
42     } else if(d + a.r <= b.r) {
43         ans -= 4. / 3 * pi * powl(a.r, 3);
44     } else {
45         long double t = (d*d + a.r*a.r - b.r*b.r) / (2.0 * d);
46         long double h = sqrt((a.r*a.r) - (t*t)) * 2.0;//h1=h2,球冠的高
47         long double l1 = ((a.r*a.r - b.r*b.r) / d + d) / 2.0;
48         long double l2 = d - l1;
49         long double x1 = a.r - l1, x2 = b.r - l2;//分别为两个球缺的高度
50         long double v1 = pi*x1*x1*(a.r - x1 / 3.0);//相交部分r1圆所对应的球缺部分体积
51         long double v2 = pi*x2*x2*(b.r - x2 / 3.0);//相交部分r2圆所对应的球缺部分体积
52         long double v = v1 + v2;//相交部分体积
53         ans-=v;
54     }
55     cout << setprecision(10) << fixed << ans << endl;
56 }










猜你喜欢

转载自www.cnblogs.com/zllwxm123/p/10459680.html