本场练习赛状态还是挺不错的,有些慢热,有思路,做的比较慢,但也坚持写下来了。
A Gym 101981A Adrien and Austin
类型
博弈
题意
一共有n个石子,编号分别为 1 - n,有两个人分别是Adrien、 Austin,Adrien先手。每个人可以取1~k个连续的石子,注意题目要求是连续的,最后不能进行取石子操作的人判负
题解
是如何思考的呢?我们从一下几组样例入手的
- n k
- 3 2
- 4 2
- 5 2
- 6 2
-
□□□
Adrien 取中间位置,只取一个
那么接下来的一手最多也只能去一个,必然会剩下一手,所以Adrien必胜(此种情况先手必胜) -
□□□□
Adrien 取中间两个,发现也是先手必胜,所以□□□必胜 -
□□□□□
5 2的情况会复杂一些,慢点想也是很容易想清楚的
先手取 1 个 取最左端,
那我后手想取胜,我就取位置3~4两个石子
我的ac代码
int main(){
int n, k;
scanf("%d%d",&n,&k);
if (n == 0){
printf("Austin\n");
return 0;
}
for(int i = 1; i <= k; i++){
if ((n - i) % 2== 0) {
printf("Adrien\n");
return 0;
}
}
printf("Austin\n");
return 0;
}
正解的ac代码
int main()
{
int n,k;
scanf("%d %d",&n,&k);
if(n==0) printf("Austin\n");
else if(k==1)
{
if(n%2) printf("Adrien\n");
else printf("Austin\n");
}
else printf("Adrien\n");
return 0;
}
B Gym 101981B Tournament
C Gym 101981C Cherry and Chocolate
题意
Cherry 和 Chocolate 在一个树形图上进行游戏。Cherry用粉色进行涂画节点,而Chocolate用棕色进行涂画节点,轮流进行涂画节点,Cherry是先手。当没有路径能连接将要涂画的节点和原先属于自己的颜色节点的时候则无法进行涂画。
每涂画一个点得一分,题目要求Cherry的分数最大化而Chocolate最小化.
题解
无题解
D Gym 101981D Country Meow
题意
给定n个城市的坐标,要求建立一个战略所,要求距离最远的城市的欧几里得距离最小
题解
通过题目能够很清楚的知道需要能够到达所有城市,又要求距离最小,因此就可以考虑到最小覆盖圆,然后题目是三维的,于是就是寻找三维最小覆盖圆
【模板题】
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const double eps = 1e-8;
const int inf = 0x3f3f3f3f;
const double start_T = 1000;
//最小包围球
struct point3d
{
double x,y,z;
}data[150];
int n;
double dis(point3d a, point3d b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
double solve()
{
double step=start_T,ans=inf,mt;
point3d z;
z.x=z.y=z.z=0;
int s=0;
while(step>eps)
{
for (int i = 0; i < n; ++i)
{
if (dis(z,data[s])<dis(z,data[i])) s=i;
}
mt=dis(z,data[s]);
ans=min(ans,mt);
z.x+=(data[s].x-z.x)/start_T*step;
z.y+=(data[s].y-z.y)/start_T*step;
z.z+=(data[s].z-z.z)/start_T*step;
step*=0.97;
}
return ans;
}
int main(){
cin >> n;
for(int i = 0; i < n; i++){
scanf("%lf%lf%lf",&data[i].x,&data[i].y,&data[i].z);
}
double ans = solve();
printf("%.10f\n", ans);
}
E Gym 101981E Eva and Euro coins
题意
翻硬币,每个人可以翻动连续的k个相同硬币,问能够从字符串1的状态翻转到字符串2的状态
题解
可以发现
使用规约的思想,当字符串中出现连续的k个1或者是k个0就直接进行删除操作,直到不能删除为止,对两个字符串都进行如此操作,如果最后剩下的两个字符串是相等的,就输出Yes否则就输出No
由于在经过删除操作后可能出现新的连续k串,所以需要运用一个栈这个数据结构去处理。
有人可能会疑问逐个比较后移为什么会是错的
因为要求翻转的是 相同 的
const int MOD = int(1e9) + 7;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6 + 20;
const int N = 2e5 + 50;
int n, k;
int cnt[maxn], st[maxn];
string F(string s){
if (k == 1) return "";
int top = 0; // 栈顶
for(int i = 0; i < n; i++) {
if (top && st[top] == s[i] - '0'){
//栈非空且顶部与即将要放入的相等
cnt[top]++;
if (cnt[top] == k) top--;
//如果放了k个了,那么前面那k个就可以删除了
}
else {
st[++top] = s[i] - '0';
cnt[top] = 1;
}
}
s = "";
for(int i = 1; i <= top; i++){
while(cnt[i]) {
s += st[i];
cnt[i]--;
}
}
return s;
}
int main(){
cin >> n >> k;
string s1, s2;
cin >> s1 >> s2;
if (F(s1) == F(s2)) printf("Yes\n");
else printf("No\n");
}
F Gym 101981F Frank
题解
无题解
G Gym 101981G Pyramid
题意
要求你计算出该三角形中有多少个三角形(题目的黑线是给出提示,这么也算是一个三角形)
题解
题目类型应该是算 数学、找规律
前几项还是比较好算的:
1 , 5 , 15 , 35 , 70 , 126 , 210 … … 1,5,15,35,70, 126,210… … 1,5,15,35,70,126,210……
第一次做差:4,10,20,35 ,56, 84
第二次做差:6 10 15 21 28
第三次做差:4,5,6,7
第四次做差:1,1,1,1
所以这是一个四阶的方程式(相当于求导四次是一个常数),那么递推公式应该是:
f ( n ) = a ∗ n 4 + b ∗ n 3 + c ∗ n 2 + d ∗ n + e f(n) = a*n^4 + b*n^3 + c*n^2 + d*n + e f(n)=a∗n4+b∗n3+c∗n2+d∗n+e
将前五项带入,得五个方程求出a,b,c,d,e
最后算出来是:
a a a = 1 24 \frac{1}{24} 241
b b b = 6 24 \frac{6}{24} 246
c c c = 11 24 \frac{11}{24} 2411
d d d = 6 24 \frac{6}{24} 246
e e e = 0 0 0
所以递推公式为: f(n) = ( n 4 + 6 ∗ n 3 + 11 ∗ n 2 + 6 ∗ n ) 24 \frac{(n^4 + 6*n^3 + 11*n^2 +6*n)}{24} 24(n4+6∗n3+11∗n2+6∗n)
int main()
{
int t;
ll n;
scanf("%d",&t);
while(t-- && scanf("%lld" ,&n) != EOF){
printf("%lld\n",n * (n+1) % mod * (n+2) % mod * (n+3) % mod * inv % mod);
}
return 0;
}
H Gym 101981H Huge Discount
题意
有n个英雄和m个怪物。
每个英雄能够击杀一个自己所能击杀的怪物。
有k瓶魔法药水,每瓶魔法药水能够使英雄多获得一次击杀怪物的机会,但每个英雄最多使用一次魔法药水。
题解
二分图的最大匹配问题。
思路是这样子的:首先先跑一遍二分图匹配,让每个英雄都匹配一个怪物去进行击杀,然后把已经击杀的怪物删去,再跑一遍匹配,第二遍匹配的结果数量如果超过k只,那么其结果就只能是k,因为只有k瓶药水,如果小于k则不用改变。
板子的话可以去acwing上查看y总的。
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 510, M = 100010;
int n, k, m;
int h[N], e[M], ne[M], idx;
int match[N];
bool st[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
bool find(int x)
{
for (int i = h[x]; i != -1; i = ne[i])
{
int j = e[i];
if (!st[j])
{
st[j] = true;
if (match[j] == 0 || find(match[j]))
{
match[j] = x;
return true;
}
}
}
return false;
}
int main()
{
cin >> n >> m >> k;
memset(h, -1, sizeof(h));
for(int i = 1; i <= n; i++){
int mi; cin >> mi;
for(int j = 1; j <= mi; j++){
int b; cin >> b;
add(i, b);
}
}
int res = 0;
for (int i = 1; i <= m; i ++ )
{
memset(st, false, sizeof st);
if (find(i)) res ++ ;
}
int res2 = 0;
for (int i = 1; i <= m; i ++ )
{
memset(st, false, sizeof st);
if (find(i)) res2 ++ ;
}
printf("%d\n", res + min(res2, k));
return 0;
}