A. Abiyoyo、
题意
输出n个Abiyoyo, Abiyoyo.在输出两个Abiyoyo, yo yoyo yo yoyo.
代码
#include<iostream>
using namespace std
;
int main(){
int T
;
scanf("%d",&T
);
while(T
--){
int n
;
scanf("%d",&n
);
while(n
--){
puts("Abiyoyo, Abiyoyo.");
}
puts("Abiyoyo, yo yoyo yo yoyo.");
puts("Abiyoyo, yo yoyo yo yoyo.");
}
return 0;
}
E The Champion
题意
给了r,k,p 三个数,表示一用有 2r 给人,当前这个人在第k个强,如果强的人和弱的人打获胜的概率为p,求这个人获胜的最大可能
思路
如果一个要想获得胜率的可能性最大,那么他应该尽可能先和比他弱的人打(先和获胜概率大的人比赛,否则这个概率会一直在比赛中间接性的减小),争取强的人淘汰更多强的人,按照这个贪心的思路,如果有弱的人,那么就和弱的人打,就只能和强的人打,那么弱的人应该淘汰的尽可能少,所以弱的和弱的打,强的和强的打,对于有一个弱的和一个强的的情况单独处理,就可以使用dfs的思路,统计每次的剩下的强和弱 人的个数,然后继续递归,直到这个人获胜
代码
#include<iostream>
#include<cstring>
#include<map>
using namespace std
;
#define x first
#define y second
typedef pair
<int ,int > PII
;
#define int long long
int r
,k
;
double p
;
map
<PII
,double > mp
;
double dfs(int higher
,int lower
){
if(higher
== 0&& lower
== 0) return 1;
if(mp
.count({higher
,lower
})) return mp
[{higher
,lower
}];
auto &v
= mp
[{higher
,lower
}];
if(lower
& 1){
return v
= p
* dfs(higher
/2,lower
/2);
}
else{
if(lower
!= 0){
return v
= p
* (p
* dfs(higher
/2 + 1,lower
/2 - 1) + (1 - p
) * dfs(higher
/2,lower
/2));
}
else{
return v
= (1 - p
) * dfs(higher
/2,0);
}
}
}
signed main(){
int T
;
cin
>>T
;
while(T
--){
mp
.clear();
scanf("%lld%lld%lf",&r
,&k
,&p
);
r
= 1ll<<r
;
int higher
= k
- 1,lower
= r
- k
;
if(p
< 0.5) swap(higher
,lower
), p
= 1 - p
;
double res
= dfs(higher
,lower
);
printf("%.6lf\n",res
);
}
return 0;
}
F. The Chosen One
题意
有n个人站成一排,每次会淘汰奇数位置的人,然后在剩余人中继续淘汰,只到最后一个人为为止,求最后一个人的编号
思路
我们在每k次淘汰中只会剩下 2k的倍数的人,那么最后一次人的编号就是2k,且不存在他的倍数,即不存在2k+1这个编号
代码
T
= int(input(""))
while T
:
T
-= 1
n
= int(input(""))
ans
= 1
while ans
* 2 <= n
:
ans
*= 2
print(ans
)
H. The Game of Life
题意
给定几个细胞在无限大的平面上扩展,默认其余细胞都是死的,求在0 - 321次中最多的细胞是哪次,个数为多少,321次有多少个细胞 细胞的成活满足 1.如果活细胞的周围小于2个或大于3个那么他就会死 2.活细胞只有周围有2个或三个才能存活到下一次 3.死细胞的周围有精确地3个就活
思路
就是简单的模拟,但是卡常,一直过不去,参考别人的代码写的
代码
#include<iostream>
#include<cstring>
#include<set>
#include<vector>
using namespace std
;
#define x first
#define y second
typedef pair
<int ,int > PII
;
const int N
= 1010,M
= 350;
bool a
[N
][N
];
set
<PII
> s
;
vector
<PII
> live
,died
;
int dx
[] = {1,-1,0,0,1,1,-1,-1};
int dy
[] = {0,0,1,-1,1,-1,1,-1};
char str
[10];
void insert(int x
,int y
){
for(int i
= -1;i
<=1;i
++)
for(int j
= -1;j
<=1;j
++)
s
.insert({x
+ i
,y
+ j
});
}
int get(int x
,int y
){
int t
= 0;
for(int i
= 0;i
<8;i
++){
int p
= x
+ dx
[i
],q
= y
+ dy
[i
];
if(a
[p
][q
]) t
++;
}
return t
;
}
int main(){
int T
;
scanf("%d",&T
);
while(T
--){
memset(a
,0,sizeof a
);
s
.clear();
int n
,m
;
scanf("%d%d",&n
,&m
);
int sum
= 0;
for(int i
= 0;i
< n
; i
++){
scanf("%s",str
);
for(int j
= 0;j
< m
; j
++)
{
if(str
[j
] == '#'){
int x
= i
+ M
,y
= j
+ M
;
insert(x
,y
);
sum
++;
a
[x
][y
] = true
;
}
}
}
int max_id
= 0,max_s
= sum
;
for(int i
= 1;i
<= 321;i
++){
live
.clear();
died
.clear();
for(auto it
:s
){
int x
= it
.x
,y
= it
.y
;
if(a
[x
][y
]){
int t
= get(x
,y
);
if(t
== 2||t
== 3) continue;
died
.push_back({x
,y
});
sum
--;
}
else{
int t
= get(x
,y
);
if(t
== 3) live
.push_back({x
,y
}),sum
++;
}
}
if(sum
> max_s
) max_id
= i
,max_s
= sum
;
for(auto it
:live
){
insert(it
.x
,it
.y
);
a
[it
.x
][it
.y
] = true
;
}
for(auto it
:died
){
a
[it
.x
][it
.y
] = false
;
}
}
printf("%d %d %d\n",max_id
,max_s
,sum
);
}
return 0;
}
I. Rake It In
题意
给定一个4 * 4的地方,有两个人,他们分别选一块2 * 2的地方,并把上面的分数加到总分且这四个单元格会逆转,每个人分别操作k次第一个人想让总分最大,第二个人想让总分最小,求最后的总分数
思路
因为每次的范围很小很小,而且单元的也很小就可以直接考虑爆搜,如果第一个人就选择地方的分数 + 他和第二个人之后的操作分数 中最大的那个,第二个也是同样,只不过找分数最小的地方
代码
#include<iostream>
#include<cstring>
using namespace std
;
const int N
= 10;
int g
[N
][N
];
int n
;
int dfs(int u
){
if(u
== 2 * n
) return 0;
int res
= 0;
if(u
%2) res
= 0x3f3f3f3f;
for(int i
= 0;i
<=2;i
++)
for(int j
= 0;j
<=2;j
++)
{
int a
= g
[i
][j
],b
= g
[i
][j
+ 1];
int c
= g
[i
+1][j
],d
= g
[i
+ 1][j
+ 1];
g
[i
][j
] = b
,g
[i
][j
+ 1] = d
,g
[i
+ 1][j
+ 1] = c
,g
[i
+1][j
] = a
;
if(u
%2) res
= min(res
,dfs(u
+ 1) + a
+ b
+ c
+ d
);
else res
= max(res
,dfs(u
+ 1) + a
+ b
+ c
+ d
);
g
[i
][j
] = a
,g
[i
][j
+1] = b
,g
[i
+ 1][j
] = c
,g
[i
+ 1][j
+ 1] = d
;
}
return res
;
}
int main(){
int T
;
scanf("%d",&T
);
while(T
--){
scanf("%d",&n
);
for(int i
= 0;i
<4;i
++)
for(int j
= 0;j
<4;j
++)
scanf("%d",&g
[i
][j
]);
cout
<<dfs(0)<<endl
;
}
return 0;
}
J. Rearrangement
题意
给定一个2 * n的序列,请对它们重新排列,使得相邻的两个数的之和不是三的倍数
思路
我们可以间接的想,只用考虑%3的余数,其中余数为1和为2的不能相邻,但是他们可以和余数为0的相邻,余数为0的只要不和自己相邻即可 首先,考虑余数为0的不能自己相邻,即余数为0的个数只用不大于n即可 其次,考虑余数为1和为2的不能相邻,那么我们可以把余数为1的放在一边,余数为2的放在另一边中间使用两个余数为0的建立分割线,(剩余的余数为0的可以按照余数为1或余数为2分别处理)如果余数为0的小于两个且余数为1和为2的都存在那么他们必然相邻, 特殊情况 只有2个余数为0时,余数为1的个数必须为奇数,因为隔离的两边都能只能有奇数个
111022
110222
或者
110222
111022
都是奇数个,余数为0大于三可以给余数为1或2自由分配这不需要考虑这种情况
代码
#include<iostream>
#include<cstring>
using namespace std
;
int cnt
[3];
int main(){
int T
;
scanf("%d",&T
);
while(T
--){
int n
;
memset(cnt
,0,sizeof cnt
);
scanf("%d",&n
);
for(int i
= 1;i
<=2 * n
;i
++){
int x
;
scanf("%d",&x
);
int v
= x
%3;
cnt
[v
]++;
}
bool flag
= true
;
if(cnt
[0] > n
){
flag
= false
;
}
if(cnt
[0] <= 2 &&(cnt
[1]&&cnt
[2])){
if(cnt
[0] < 2)
flag
= false
;
if(cnt
[0] == 2 &&(cnt
[1]%2 == 0&&cnt
[2]%2==0)){
flag
= false
;
}
}
if(flag
) puts("YES");
else puts("NO");
}
return 0;
}
L. Twice Equation
题意
给出L,求不小于L的满足 2m(m + 1) = n(n + 1)的最小m
思路
不会推公式,打表加在 推公式网站上搜 公式 a0 = 0,a1 = 3, an = 6 * an-1 - an-2 + 2
代码
T
= int(input(""))
while T
:
T
-= 1
n
= int(input(""))
a
= 0
b
= 3
while a
< n
:
t
= 6 * b
- a
+ 2
a
= b
b
= t
print(a
)
M. The Maximum Unreachable Node Set
题意
给定一个DAG(有向图),求有向图的最大独立集,即最大的不可达点集
思路
总个数 - 最小覆盖数,最小覆盖数就是二分图的最大匹配数 可以先用Floyd算法求出所有点的可达点
代码
#include<iostream>
#include<cstring>
using namespace std
;
const int N
= 110;
int match
[N
];
bool st
[N
];
bool g
[N
][N
];
int n
,m
;
bool
find(int u
){
for(int i
=1;i
<=n
;i
++){
if(!g
[u
][i
]||st
[i
]) continue;
int t
= match
[i
];
st
[i
] = true
;
if(t
== 0||find(t
)){
match
[i
] = u
;
return true
;
}
}
return false
;
}
int main(){
int T
;
scanf("%d",&T
);
while(T
--){
memset(match
,0,sizeof match
);
memset(g
,0,sizeof g
);
scanf("%d%d",&n
,&m
);
while(m
--){
int a
,b
;
scanf("%d%d",&a
,&b
);
g
[a
][b
] = true
;
}
for(int k
= 1;k
<=n
;k
++)
for(int i
= 1;i
<=n
;i
++)
for(int j
= 1;j
<=n
;j
++)
g
[i
][j
]|=g
[i
][k
]&g
[k
][j
];
int res
= 0;
for(int i
= 1;i
<=n
;i
++){
memset(st
,0,sizeof st
);
if(find(i
)) res
++;
}
printf("%d\n",n
- res
);
}
return 0;
}