比赛传送门 作者: fn
签到题
1010题 Smzzl with Tropical Taste / Smzzl与热带风味冰红茶
题目大意 游泳池里有
V
V
V 升的冰红茶,开始时
V
=
1
V=1
V=1升, 主人倒冰红茶的速度是
q
V
qV
qV 升/秒(速度是
V
V
V 的正比例函数),男孩喝冰红茶的速度是
p
V
pV
pV 升/秒,喝完为止。
给定
p
,
q
p,q
p,q ,求解:对于任意
G
>
0
G>0
G>0 ,是否存在一个
T
>
0
T>0
T>0 ,对于任意
t
>
T
t>T
t>T ,男孩在
t
t
t 秒后喝了超过
G
G
G 升的冰红茶。
考察内容 数学
分析 当
p
>
q
p>q
p>q 时,喝冰红茶的数量有限;当
p
≤
q
p≤q
p≤q 时,喝冰红茶的数量无限。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,m;
int main(){
ios::sync_with_stdio(0); cin.tie(0);
int t; cin>>t;
double p,q;
while(t--){
cin>>p>>q;
if(p<=q){
cout<<"N0 M0R3 BL4CK 1CE TEA!"<<endl;
}
else{
cout<<"ENJ0Y YOURS3LF!"<<endl;
}
}
return 0;
}
基本题
1008题 Smzzl with Greedy Snake / Smzzl与贪吃蛇
题目大意 Smzzl要为贪吃蛇做一个AI。
在这个游戏中,蛇需要1单位的时间向前移动1单位的长度。 蛇旋转90度也需要1单位的时间。 最初地图上有一种食物。 蛇吃完每一种食物后,下一种食物就出现了。
Smzzl当然希望蛇尽可能快地吃完食物,所以他需要尽量减少蛇吃每一种食物的时间。 请输出一个有效的操作序列。
考察内容 模拟
分析 这道题中只考虑蛇头,蛇没有长度。所以在吃每个食物时尽可能直走,根据食物所在的方向和当前蛇头的方向分类讨论,模拟走最短路径的过程即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+10;
ll n,m,a[N];
int X[4]={0,1,0,-1}, Y[4]={1,0,-1,0};
int main(){
ios::sync_with_stdio(0); cin.tie(0);
int t; cin>>t;
ll x,y,d;
while(t--){
cin>>x>>y>>d;
cin>>n;
ll x2,y2;
for(int i=1;i<=n;i++){
cin>>x2>>y2;
ll dx=x2-x,dy=y2-y;
if(dx>0 && dy>0){
if(d==0){
for(int i=1;i<=dy;i++)
cout<<'f';
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dx;i++)
cout<<'f';
}
else if(d==1){
for(int i=1;i<=dx;i++)
cout<<'f';
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dy;i++)
cout<<'f';
}
else if(d==2){
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dx;i++)
cout<<'f';
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dy;i++)
cout<<'f';
}
else{
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dy;i++)
cout<<'f';
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dx;i++)
cout<<'f';
}
}
else if(dx<0 && dy<0){
dx=abs(dx),dy=abs(dy);
if(d==0){
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dx;i++) cout<<'f';
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dy;i++) cout<<'f';
}
else if(d==1){
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dy;i++) cout<<'f';
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dx;i++) cout<<'f';
}
else if(d==2){
for(int i=1;i<=dy;i++) cout<<'f';
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dx;i++) cout<<'f';
}
else{
for(int i=1;i<=dx;i++) cout<<'f';
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dy;i++) cout<<'f';
}
}
else if(dx>0 && dy<0){
dx=abs(dx),dy=abs(dy);
if(d==0){
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dx;i++) cout<<'f';
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dy;i++) cout<<'f';
}
else if(d==1){
for(int i=1;i<=dx;i++) cout<<'f';
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dy;i++) cout<<'f';
}
else if(d==2){
for(int i=1;i<=dy;i++) cout<<'f';
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dx;i++) cout<<'f';
}
else{
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dy;i++) cout<<'f';
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dx;i++) cout<<'f';
}
}
else if(dx<0 && dy>0){
dx=abs(dx),dy=abs(dy);
if(d==0){
for(int i=1;i<=dy;i++) cout<<'f';
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dx;i++) cout<<'f';
}
else if(d==1){
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dy;i++) cout<<'f';
cout<<'u'; d=(d+3)%4;
for(int i=1;i<=dx;i++) cout<<'f';
}
else if(d==2){
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dx;i++) cout<<'f';
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dy;i++) cout<<'f';
}
else{
for(int i=1;i<=dx;i++) cout<<'f';
cout<<'c'; d=(d+1)%4;
for(int i=1;i<=dy;i++) cout<<'f';
}
}
else if(dx==0){
if(dy>0){
if(d==0){
}
else if(d==1){
cout<<'u'; d=(d+3)%4;
}
else if(d==2){
cout<<'c'; cout<<'c'; d=(d+1)%4; d=(d+1)%4;
}
else{
cout<<'c'; d=(d+1)%4;
}
for(int i=1;i<=dy;i++){
cout<<'f';
}
}
else{
dy=-dy;
if(d==0){
cout<<'c'; cout<<'c'; d=(d+1)%4; d=(d+1)%4;
}
else if(d==1){
cout<<'c'; d=(d+1)%4;
}
else if(d==2){
}
else{
cout<<'u'; d=(d+3)%4;
}
for(int i=1;i<=dy;i++){
cout<<'f';
}
}
}
else if(dy==0){
if(dx>0){
if(d==0){
cout<<'c'; d=(d+1)%4;
}
else if(d==1){
}
else if(d==2){
cout<<'u'; d=(d+3)%4;
}
else{
cout<<'u'; d=(d+3)%4; cout<<'u'; d=(d+3)%4;
}
for(int i=1;i<=dx;i++) cout<<'f';
}
else{
dx=-dx;
if(d==0){
cout<<'u'; d=(d+3)%4;
}
else if(d==1){
cout<<'c'; d=(d+1)%4; cout<<'c'; d=(d+1)%4;
}
else if(d==2){
cout<<'c'; d=(d+1)%4;
}
else{
}
for(int i=1;i<=dx;i++) cout<<'f';
}
}
x=x2;
y=y2;
}
cout<<endl;
}
return 0;
}
1007题 Link with Limit / Link与极限
题目大意 Link有一个函数
f
(
x
)
f(x)
f(x) ,其中
x
x
x 和
f
(
x
)
f(x)
f(x) 都是
[
1
,
n
]
[1,n]
[1,n] 中的整数。
设
f
n
(
x
)
=
f
(
f
n
?
1
(
x
)
)
f_n(x)=f(f_{n?1}(x))
fn?(x)=f(fn?1?(x)) ,
f
1
(
x
)
=
f
(
x
)
f_1(x)=f(x)
f1?(x)=f(x) ,关于
x
x
x 的函数
g
(
x
)
g(x)
g(x) 为:
g
(
x
)
=
lim
?
n
→
+
∞
1
n
∑
i
=
1
n
f
i
(
x
)
g (x) =\lim\limits_{n→+∞}\frac{1}{n}∑\limits_{i = 1}^{n}f_i (x)
g(x)=n→+∞lim?n1?i=1∑n?fi?(x)
他想知道对于所有
x
∈
[
1
,
n
]
x∈[1,n]
x∈[1,n] ,
g
(
x
)
g(x)
g(x) 是否相同。
考察内容 数学,图论,dfs
分析 第一步:数学 分析
g
(
x
)
g (x)
g(x) ,其中
f
i
(
x
)
f_i(x)
fi?(x) 的意思就是对
x
x
x 套用
i
i
i 次
f
(
x
)
f(x)
f(x) 。 建一张有向图,点
x
x
x 向点
f
(
x
)
f(x)
f(x) 连边,那么
f
f
f 迭代的过程实质上是在图上行走的过程。
x
x
x 和
f
(
x
)
f(x)
f(x) 都是
[
1
,
n
]
[1,n]
[1,n] 中的整数,所以必然会形成环。
n
→
+
∞
n→+∞
n→+∞ 时,只有环上的点权才会对极限有影响。原题转化为问每一个环的点权平均值是否相同。
第二步:图论 找出所有环并求出点权平均值。
先连上反向边。利用 dfs 遍历结点找环,找到时计算点权平均值,然后反向遍历所有可以到达这个环的结点,这些结点的
g
(
x
)
g (x)
g(x) 都是相同的,不会对答案造成影响,之后不再遍历。 复杂度
O
(
n
)
O(n)
O(n) 。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
ll n,m,f[N],an;
vector<int> f2[N];
int loop[N];
double sum=0,ans=0;
double g[N];
ll ff[N];
int vis[N];
void dfs2(int x){
if(loop[x]==1)return;
loop[x]=1;
for(auto e:f2[x]){
dfs2(e);
}
}
void dfs(int x,ll cnt){
if(an==0)return;
ff[x]=sum;
sum+=f[x];
vis[x]=cnt;
g[x]=sum;
if(vis[f[x]]==0){
dfs(f[x],cnt+1);
return;
}
else{
dfs2(x);
int s=cnt-vis[f[x]]+1;
if(s==0) return;
sum=(g[x]-ff[f[x]])*1.0/s;
if(ans==0) ans=sum;
if(ans!=sum) an=0;
}
return;
}
void init(int n){
memset(g,0,sizeof(g[0])*(n+1));
memset(ff,0,sizeof(ff[0])*(n+1));
memset(f,0,sizeof(f[0])*(n+1));
memset(loop,0,sizeof(loop[0])*(n+1));
memset(ff,0,sizeof(ff[0])*(n+1));
memset(vis,0,sizeof(vis[0])*(n+1));
for(int i=1;i<=n;i++){
f2[i].clear();
}
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
int t; cin>>t;
while(t--){
cin>>n;
init(n);
an=1;
ans=0;
sum=0;
for(int i=1;i<=n;i++){
cin>>f[i];
f2[f[i]].push_back(i);
}
for(int i=1;i<=n;i++){
if(loop[i]==0){
sum=0;
dfs(i,1);
}
}
if(an==0) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
return 0;
}
1003题 Fall with Trees / Fall与树
题目大意 Fall想要画一个完美的二叉树。
我们首先规定树中所有具有相同深度的节点在平面上也具有相同的y坐标。 将相同深度的节点定义为相同层次的节点,那么完美二叉树有四个属性。
- 满二叉树。
- 相邻两层节点的y坐标差为常数。
- 同一层次上两个相邻节点的x坐标差为常数。
- 每个节点的x坐标是其子节点x坐标的平均值。
Fall已经画出了这个二叉树的根节点和它的左右两个子节点。 现在Fall打算画出总共k个层次,他想知道这个完美二叉树的所有节点的凸包的面积是多少。
完美二叉树的例子:
考察内容 数学,等比数列求和
分析 等比数列求每一层的面积和
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int k,t,x0,y0,x1,y1,x2,y2;
int main(){
cin>>t;
while(t--){
scanf("%d",&k);
scanf("%d%d%d%d%d%d",&x0,&y0,&x1,&y1,&x2,&y2);
ll d=x2-x1,h=y0-y1,S=(2ll*k-5)*d*h,p=60000ll*d*h;
for (int i=1;i<=k&&p;i++) p>>=1;
S+=p/10000,p%=10000,k=p%10,p/=10;
printf("%lld.%03lld\n",S,p+(k>=5));
}
}
进阶题
1012题 Yiwen with Sqc / Yiwen和字符串
题目大意 定义权值为区间里面每个字母出现次数的平方和,给定一个字符串,计算字符串所有子区间的权值和。
考察内容 差分,字符串,复杂度优化
分析 不同字母之间没有影响,分别考虑每一种字母。
#include<bits/stdc++.h>
using namespace std;
const int P = 998244353;
int n;
char ch[200005];
int solve(vector<int> vec){
vec.push_back(n+1);
int ans=0,per=0,dif=0;
for (int i=1;i<vec.size();i++){
ans=(1ll*ans+1ll*per*(vec[i]-vec[i-1]))%P;
dif=(1ll*dif+2ll*vec[i-1]+vec[i]-vec[i-1])%P;
per=(per+dif)%P;
}
return ans;
}
void solve(){
scanf("%s",ch+1);
n=strlen(ch+1);
ch[n+1]='\0';
vector<int> a[28];
for (int i=0;i<=25;i++) a[i].push_back(0);
for (int i=1;i<=n;i++) {
a[ch[i]-'a'].push_back(i);
}
int ans=0;
for (int i=0;i<=25;i++) {
ans=(ans+solve(a[i]))%P;
}
printf("%d\n",ans);
}
int main(){
int t;
scanf("%d",&t);
while (t--) solve();
}
|