比赛传送门
作者:WHy
目录
签到题
1004题 Link with Equilateral Triangle
题目大意
给定边长为n的大等边三角形,将其完全分割为边长为1的小等边三角形,在小等边三角形的顶点填数,大三角形的左边不允许填0,右边不允许填1,底边不允许填2,小三角形三顶点数和不可为3的倍数,输入大三角形边长,输出是否可以填出数据。
考察内容
找规律
分析
证明:
对于一个合法的解,应当满足不存在同时包含0,1,2的三角形,下面我们证明这样的三角形一定存在。
左下角必然是1,右下角必然是0,底边不能含有2,则底边上必然有奇数条1-0的边,这些边都属于一个
小三角形。考虑其他的0-1边,由于不在两个斜边上,其他的0-1边必然属于两个三角形。因此“每个三角
形内0-1边的数量”的和必然为奇数。
但是,假设不存在0-1-2的三角形,则所有三角形都必然包含0条或2条的0-1边,产生了矛盾。
因此一定存在0-1-2的三角形。
因此输出一堆"No"即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+7;
void solve(){
char s[N],ans[N];
int k=0;
cin>>s;
for(int i=0;i<strlen(s);i++){
if(s[i]==','||s[i]=='-'||s[i]=='('||s[i]==')'||s[i]>='0'&&s[i]<='9')ans[k++]=s[i];
}
ans[k]='\0';
cout<<ans<<endl;
}
int main(){
int t;
cin>>t;
while(t--)solve();
}
1006题 BIT Subway
题目大意
地铁票买100元以上八折,200元以上五折,DLee理解为总价格,实为单票价,输出DLee理解的价格和实际价格
考察内容
模拟
分析
按照DLee理解,要到200元,实际票价应为225元,故输出即求解分段方程
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
void solve(){
int n,i,a[N];
double ans1=0,ans2=0;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
ans1+=a[i];
if(ans2<100)ans2+=a[i];
else if(ans2>=100&&ans2<200)ans2+=0.8*a[i];
else ans2+=0.5*a[i];
}
if(ans1>=225)ans1=200+0.5*(ans1-225);
else if(ans1>=100)ans1=100+0.8*(ans1-100);
printf("%.3lf %.3lf\n",ans1,ans2);
}
int main(){
int t;
cin>>t;
while(t--)solve();
}
基本题
1007题 Climb Stairs
题目大意
往上爬n层塔,可以选择往上跳1-k格或往下走一格,不可走走过的地方,角色有一初始战斗力,要大于等于要去的层的战斗力才可去,并将该层战斗力加入自己的战斗力,询问是否能到达所有层
考察内容
贪心,复杂度优化
分析
从能去的最低层到能去的最高层扫描,一旦到能去的地方就去,此处能去指的是可以吃掉去的那一层并顺势吃掉知道能去的最底层的所有层。
笔者一开始想的是使用一个函数从上往下扫描是否能去,结果TLE,优化算法,引入need函数标记要去每一层所需的初始战斗力。
循环退出不当也会导致WA,引入变量,每到一层就加一,变量到n时说明经过每一层,如果一轮扫描没有符合条件的层,说明并不能完成。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
void solve(){
int n,k,l,r,i;
long long a;
long long h[N],need[N];
cin>>n>>a>>k;
h[0]=0;
need[0]=0;
for(i=1;i<=n;i++)cin>>h[i];
for(i=1;i<=n;i++)need[i]=max(need[i-1]-h[i],h[i]);//构造need数组,能吃掉一层即要顺势吃掉上一层,以此类推
l=1;
r=min(k,n);//右端点不可超出最大层数
int p=0;//标记循环是否退出
while(p<n){
for(i=l;i<=r;i++){
if(a>=need[i]){
for(int j=i;j>=l;j--)a+=h[j],p++;
r=min(l+k,n);//控制右端点
l=i+1;
break;
}
}
if(i>r){//一轮扫描没有符合条件的层,符合此条件时r不会更新,不符合时r只会往更大更新,不需要考虑r的更新
cout<<"NO"<<endl;
return;//一处不满足条件即可退出
}
}
cout<<"YES"<<endl;
}
int main(){
int t;
cin>>t;
while(t--)solve();
}
进阶题
1001题 Link with Bracket Sequence II
题目大意
输入正整数a代表第a种括号的左半边,负整数-a代表第a种括号的右半边,0代表待填的数据,计算有多少种填补方案使括号序列可以互相匹配。
考察内容
区间dp
分析
用f[i][j]表示[i,j]上满足i,j上括号相匹配的方案数
g[i][j]表示[i,j]上总方案数
进行区间dp
#include<bits/stdc++.h>
using namespace std;
const int N=505;
const long long mod=1e9+7;
long long a[N],f[N][N],g[N][N];
void solve(){
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
long long n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
g[i+1][i]=1;//空区间为1
}
for(int len=2;len<=n;len+=2){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
if(a[l]>=0&&a[r]<=0){
int e=0;
if(a[l]==0&&a[r]==0)e=m;
else if(a[l]==0||a[r]==0||a[l]+a[r]==0)e=1;
f[l][r]=g[l+1][r-1]*e%mod;
}
for(int k=l;k<=r-1;k+=2){
g[l][r]+=f[l][k+1]*g[k+2][r]%mod;//枚举,用f和g保证不会重复分析
g[l][r]%=mod;
}
}
}
cout<<g[1][n]<<endl;
}
int main(){
int t;
cin>>t;
while(t--)solve();
}