Atcoder Beginner Contest 266题目分析
A - Middle Letter
计算出来字符串的长度,因为是长度为奇数的字符串,输出下标为 ( l e n + 1 ) / 2 (len+1)/2 (len+1)/2的字符即可(这里字符串下标从1开始)
#include<bits/stdc++.h>
using namespace std;
char a[110];
int main(){
cin>>a+1;
int len=strlen(a+1);
cout<<a[(len+1)/2];
}
B - Modulo Number
枚举 998244353 998244353 998244353的倍数 k k k, x = N − 998244353 ∗ k x=N-998244353*k x=N−998244353∗k,判断 x x x是否在 [ 0 , 998244353 − 1 ] [0,998244353-1] [0,998244353−1]之间,如果是则输出 x x x,如果不是则继续。并且我们可以通过 x x x的范围去计算出 k k k的范围,从而减少枚举次数。
#include<bits/stdc++.h>
using namespace std;
const long long y= 998244353;
int main(){
long long n;
cin>>n;
long long l=(n-998244352)/y-1;
long long r=n/y+1;
for(long long i=l;i<=r;i++){
long long x=n-y*i;
if(x>=0&&x<=998244352){
cout<<x;
break;
}
}
}
C - Convex Quadrilateral
题目大意,给你一个四边形,请你判断它是不是四个内角都小于180°,如果是则输出 Y e s Yes Yes,否则输出 N o No No
判断四边形内角跟180°的大小,我们可以使用叉积来计算。如果两个向量之间的叉积是小于0的则说明该内角是大于180°的。
那么到底什么是叉积呢?
在二维向量内,两个向量的叉积相当于两个向量围成的面积,即 v ⃗ × w ⃗ = ∣ v ∣ ∣ w ∣ s i n θ \vec{v} \times \vec{w} =|v| |w|sin\theta v×w=∣v∣∣w∣sinθ
注意:这里的角 θ \theta θ是 v ⃗ \vec{v} v与 w ⃗ \vec{w} w逆时针的夹角

所以在本题中我们就可以通过两个向量的叉积去判断它们的夹角是否大于180°
例如:
C D ⃗ × C B ⃗ = ∣ C D ⃗ ∣ ∣ C B ∣ ⃗ s i n θ \vec{CD}\times \vec{CB} =|\vec{CD}||\vec{CB|} sin\theta CD×CB=∣CD∣∣CB∣sinθ,为什么这里是 C D ⃗ × C B ⃗ \vec{CD}\times \vec{CB} CD×CB是因为夹角 θ \theta θ是指的从第一个向量出发,逆时针到第二个向量之间的夹角。
在坐标系中向量 C D ⃗ \vec{CD} CD的坐标可以表示成 ( x d − x c , y d − y c ) (x_d-x_c,y_d-y_c) (xd−xc,yd−yc),所以本题我们只需要注意方向,使得夹角都是内角即可。
#include<bits/stdc++.h>
using namespace std;
int cau(int a1,int b1,int a2,int b2){
return a1*b2-b1*a2;
}
int main(){
int x1,y1,x2,y2,x3,y3,x4,y4;
cin>>x1>>y1>>x2>>y2>>x3>>y3>>x4>>y4;
if(cau(x2-x1,y2-y1,x4-x1,y4-y1)<0){
cout<<"No"<<endl;
return 0;
}
if(cau(x3-x2,y3-y2,x1-x2,y1-y2)<0){
cout<<"No"<<endl;
return 0;
}
if(cau(x4-x3,y4-y3,x2-x3,y2-y3)<0){
cout<<"No"<<endl;
return 0;
}
if(cau(x1-x4,y1-y4,x3-x4,y3-y4)<0){
cout<<"No"<<endl;
return 0;
}
cout<<"Yes"<<endl;
}
D - Convex Quadrilateral
该题目很明显的具有动态规划的特征。1.他是每秒钟移动一格,可以按照时间划分问题的阶段 2.我们可以用 d p [ t ] [ p o s ] dp[t][pos] dp[t][pos]去表示Takahashi的状态,即在 t t t这个时间点Takahashi所在的位置。3.Takahashi的在时间 t t t的状态可以由在 t − 1 t-1 t−1的时间转化出来,即 d p [ t ] [ p o s ] = m a x ( d p [ t − 1 ] [ p o s − 1 ] , d p , m a x ( d p [ t − 1 ] [ p o s ] , d p [ t − 1 ] [ p o s + 1 ] ) ) + v a l u e [ p o s ] dp[t][pos]=max(dp[t-1][pos-1],dp,max(dp[t-1][pos],dp[t-1][pos+1]))+value[pos] dp[t][pos]=max(dp[t−1][pos−1],dp,max(dp[t−1][pos],dp[t−1][pos+1]))+value[pos]
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N];
int pos[N];
long long dp[N][6];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
int t1,x,a1;
cin>>t1>>x>>a1;
pos[t1]=x;
a[t1]=a1;
}
for(int i=1;i<5;i++) dp[0][i]=-1e18;
for(int i=1;i<=1e5;i++){
for(int j=0;j<5;j++){
dp[i][j]=dp[i-1][j];
if(j!=0) dp[i][j]=max(dp[i][j],dp[i-1][j-1]);
if(j!=4) dp[i][j]=max(dp[i][j],dp[i-1][j+1]);
}
dp[i][pos[i]]+=a[i];
}
long long ans=0;
for(int i=0;i<5;i++) ans=max(ans,dp[100000][i]);
cout<<ans;
}
E - Throwing the Die
期望
在第 n n n次抛掷所取得结果有两种来源,一个是本次抛掷的结果,另一个就是上一次抛掷的结果,我们取两次结果的最大值,因为是骰子所以每种结果的概率都是 1 6 \frac{1}{6} 61。那么 f ( N ) = 1 6 m a x ( 1 , f ( N − 1 ) ) + 1 6 m a x ( 2 , f ( N − 1 ) ) + 1 6 m a x ( 3 , f ( N − 1 ) ) + 1 6 m a x ( 4 , f ( N − 1 ) ) + 1 6 m a x ( 5 , f ( N − 1 ) ) + 1 6 m a x ( 6 , f ( N − 1 ) ) f(N)=\frac{1}{6}max(1,f(N−1))+\frac{1}{6}max(2,f(N−1))+\frac{1}{6}max(3,f(N−1))+\frac{1}{6}max(4,f(N−1))+\frac{1}{6}max(5,f(N−1))+\frac{1}{6}max(6,f(N−1)) f(N)=61max(1,f(N−1))+61max(2,f(N−1))+61max(3,f(N−1))+61max(4,f(N−1))+61max(5,f(N−1))+61max(6,f(N−1))
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
double ans=3.5;
for(int i=1;i<n;i++){
double ans2=0;
for(double j=1;j<=6;j++) ans2+=max(j,ans)/6;
ans=ans2;
}
printf("%.10lf",ans);
}
F - Well-defined Path Queries on a Namori
基环树
N N N个顶点 N N N条边组成的无向连通图,显然这个图中肯定有一个环,也就是我们经常说的基环树。题目问两点之间是否存在唯一一条简单路径,我们从下图中可以发现,相同颜色的点之间存在唯一一条的简单路径,但是不同颜色的点之间存在多条简单路径,所以本题的思路就很明确了:1.通过拓扑排序将环上的点找出来进行标记 2.以环上的点为根,用dfs对未被标记的点进行染色。3.判断这两点之间的颜色是否相同,如果相同就说明存在唯一一条简单路径,否则不存在

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int h[N],e[2*N],ne[2*N],idx=0;
int deg[N];
int mark[N];
queue<int>q;
void add(int x,int y){
e[++idx]=y;
ne[idx]=h[x];
h[x]=idx;
deg[y]++;
}
void topsort(){
while(q.size()){
int x=q.front();
q.pop();
for(int i=h[x];i;i=ne[i]){
int j=e[i];
deg[j]--;
if(deg[j]==1) q.push(j);
}
}
}
void dfs(int x,int fa){
mark[x]=mark[fa];
for(int i=h[x];i;i=ne[i]){
int v=e[i];
if(v==fa||deg[v]>1) continue;
dfs(v,x);
}
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++){
if(deg[i]==1) q.push(i);
}
topsort();
for(int i=1;i<=n;i++){
if(deg[i]>1){
mark[0]=i;
dfs(i,0);
}
}
int q;
cin>>q;
while(q--){
int x,y;
cin>>x>>y;
if(mark[x]!=mark[y]) cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
}
G - Yet Another RGB Sequence
题目大意:给你四个整数
R
,
G
,
B
,
K
R,G,B,K
R,G,B,K,请问有多少个只包含这R
G
B
三个字符并满足下列条件的字符串
S
S
S?答案取模
998244353
998244353
998244353后输出
- S中
R
G
B
出现的次数分别为R、G、B。 RG
作为(连续)子串在 S 中出现的次数为 K。
思路:可以先将RG看作一个整体·K
,然后将K个K
,G-K个G
,B个B
进行排列,最后再将R-K个R
插入进去,但不能插在G
的右边即可
K个K
,G-K个G
,B个B
排列有
(
b
+
k
+
g
−
k
)
!
(
g
−
k
)
!
b
!
k
!
\frac{(b + k + g-k)!}{(g-k)!b!k!}
(g−k)!b!k!(b+k+g−k)!种,接下来将剩下的R
插入进去,并且
R
R
R不能插在
G
G
G的右边,所以我们能够填
R
R
R的位置有
(
G
−
K
)
+
K
+
B
+
1
−
(
G
−
K
)
=
B
+
K
+
1
(G-K)+K+B+1-(G-K)=B+K+1
(G−K)+K+B+1−(G−K)=B+K+1
所以总共的次数 ( b + k + g − k ) ! ( g − k ) ! b ! k ! ⋅ ( ( r − k ) + s p o t s − 1 r − k ) \frac{(b + k + g-k)!}{(g-k)!b!k!} \cdot \binom{(r-k) + spots - 1}{r-k} (g−k)!b!k!(b+k+g−k)!⋅(r−k(r−k)+spots−1)
#include <bits/stdc++.h>
#include <atcoder/modint>
using namespace std;
using mint = atcoder::modint998244353;
mint fac[3000001], finv[3000001], inv[3000001];
void setup() {
const int MOD = mint::mod();
fac[0] = fac[1] = 1;
finv[0] = finv[1] = 1;
inv[1] = 1;
for(int i = 2; i <= 3000000; i++) {
fac[i] = fac[i - 1] * i;
inv[i] = (mint)MOD - inv[MOD % i] * (MOD / i);
finv[i] = finv[i - 1] * inv[i];
}
}
mint binom(int n, int r) {
if(n < r or n < 0 or r < 0) return mint::raw(0);
return fac[n] * finv[r] * finv[n - r];
}
int main() {
setup();
int r, g, b, k;
cin >> r >> g >> b >> k;
r -= k, g -= k;
mint res = fac[k + g + b] * finv[k] * finv[g] * finv[b];
res *= fac[k + b + r] * finv[r] * finv[k + b];
cout << res.val() << endl;
}
有什么不对的地方,恳望大家指出,多多交流,多多点赞嘿嘿