2021牛客寒假算法基础集训营3
比赛链接
2021牛客寒假算法基础集训营3
C.重力坠击
题目描述
在一个二维平面上有 \(n\) 个敌人,第 \(i\) 个敌人可以描述为一个以 \(\left(x_{i}, y_{i}\right)\) 为圆心, \(r_{i}\) 为半径的圆。
你每次可以对一个半径为 \(R\) 的圆范围内进行攻击(圆心自选,但圆心的横纵坐标必须为整数),对于与你攻击范围有 交点的敌人都会被消火。
你总共可以发动 \(k\) 次攻击,问最多能消多少敌人。
输入描述:
第一行以空格分隔的三个整数 \(n, k, R\) 。
接下来 \(n\) 行每行以空格分隔的三个整数 \(x_{i}, y_{i}, r_{i}\) 。
$1 \leq n \leq 10 $
$1 \leq k \leq 3 $
$1 \leq r_{i}, R \leq 7 $
\(0 \leq\left|x_{i}\right|,\left|y_{i}\right| \leq 7\)
敌人的位置可能会有重叠。
输出描述:
输出一行一个正整数代表答案。
示例1
输入
3 1 1
0 0 1
7 7 1
-2 0 1
输出
2
说明
只能发动一次攻击,可以攻击圆心为(-1,0)的圆,这样可以消灭第一个和第三个敌人。
解题思路
dfs
直接暴力枚举所有情况即可,这里千万要注意备份数组不能设置为全局变量!!!
- 时间复杂度:\(O(C_225^k)\)
代码
// Problem: 重力坠击
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/30841/C
// Memory Limit: 524288 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int res,n,k,R;
struct A
{
int x,y,r;
}a[11];
bool v[11];
void dfs(int x,int y,int cnt,int had)
{
if(cnt==k)
{
res=max(res,had);
return ;
}
if(y==8)x++,y=-7;
if(x==8)
{
res=max(res,had);
return ;
}
bool bv[11];
memset(bv,0,sizeof bv);
int c=0;
for(int i=1;i<=n;i++)
{
if(v[i])continue;
if(((x-a[i].x)*(x-a[i].x)+(y-a[i].y)*(y-a[i].y))<=(R+a[i].r)*(R+a[i].r))bv[i]=v[i]=true,c++;
}
dfs(x,y+1,cnt+1,c+had);
for(int i=1;i<=n;i++)
if(bv[i])v[i]=false;
dfs(x,y+1,cnt,had);
}
int main()
{
cin>>n>>k>>R;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y>>a[i].r;
dfs(-7,-7,0,0);
cout<<res;
return 0;
}
J.加法和乘法
题目描述
有一天牛牛和牛妹在做游戏,规则如下:
桌面上摆着\(n\)张纸牌,每张纸牌上写着一个正整数,由牛牛先手轮流执行以下操作:
\(\text 1.\)如果桌面上只剩一张纸牌,游戏结束,这张纸牌上的数字如果是奇数则牛牛胜利,反之牛妹胜利。
\(\text 2.\)当前行动玩家选择两张纸牌,设上面的数字分别为\(\mathit X,Y\),接下来玩家从加法和乘法中选择一个并应用到这两个数字上,得到结果为\(\mathit Z\),接下来将选择的两张纸牌丢弃,并拿一张新的纸牌放到桌面上,在上面写上\(\mathit Z\)。
假设双方均以最优策略行动,最后谁会赢?
输入描述:
第一行一个正整数\(\mathit n\),代表开始的纸牌数。
第二行\(\mathit n\)个空格分隔的正整数\(a_{i}\)代表开始纸牌上的数字。
\(1\leq n \leq 10^{6}\)
\(1\leq a_{i} \leq 10^{9}\)
输出描述:
如果牛牛能赢,输出\(\mathit NiuNiu\),否则输出\(\mathit NiuMei\)。
示例1
输入
3
233 2333 23333
输出
NiuMei
示例2
输入
4
1 1 1 1
输出
NiuNiu
解题思路
博弈论
首先需要特判 \(n=1\) 的情况,另外如果最后一次操作是后手操作的话,由于后手总是可以将两个数变为偶数,所以后手必胜;否则如果偶数数量至多为 \(1\),先手必胜,因为如果有偶数的话先手可以消掉这个偶数,如果后手下次再产生(至多一个)偶数,下下轮先手可以再消去,最后的操作在于先手,所以先手必胜;否则如果偶数数量大于等于 \(2\),先手必败,先手每次最多只能消掉一个偶数,而后手可以产生偶数,最后一个数一定是偶数
- 时间复杂度:\(O(1)\)
代码
// Problem: 加法和乘法
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/9983/J
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int n,res[2];
int main()
{
cin>>n;
int x;
bool f=false;
if(n==1)
{
cin>>x;
if(x&1)f=true;
}
else if(n%2==0)
{
for(int i=1;i<=n;i++)
{
cin>>x;
res[x&1]++;
}
if(res[0]<2)f=true;
}
puts(f?"NiuNiu":"NiuMei");
return 0;
}