题目链接:
file:///D:/C++/%E9%9B%86%E8%AE%AD%E6%B5%8B%E8%AF%95/1001/2022%20-%20J2.pdf
T1:隔离
题意如图。需要求所有时间的最短。
思路:
不需要进行一次次枚举,先算出总共要办事的总时间sum,如果某一次时间超过240(需要隔离)就不回来了(反正也要隔离就一直干完了在回来)如果一直没有需要隔离,就进行分类
(最后要判断来回所需要的时间和如果一直呆在B处隔离所花时间的大小)
赛时代码
#include<bits/stdc++.h>
using namespace std;
int a[100050];
int main() {
freopen("isolate.in","r",stdin);
freopen("isolate.out","w",stdout);
int n,ans=400,now=0;
cin>>n;
for(int i=1; i<=n; i++)cin>>a[i];
if(n==1)
if(a[1]>=240) ans+=10080+a[1];
else ans+=a[1];
else if(n==2)
if(a[1]>=240) ans+=10080+a[1];
else if(a[2]>=240) ans+=+10080+a[2];
else if(a[1]+a[2]<240)ans+=a[1]+a[2];
else ans+=a[1]+a[2]+400;
else
for(int i=1; i<=n; i++) {
if(a[i]>=240){
ans=ans+400+10080+a[i];
}else if(now+a[i]<240) {
ans+=a[i];
now+=a[i];
} else {
ans=ans+a[i]+400;
now=a[i];
}
}
cout<<ans;
return 0;
}//思路很混乱,看不懂了
(最后六十分)
正确代码
#include<bits/stdc++.h>
using namespace std;
int a[100050],n,sum,now,flag,cnt;
int main() {
freopen("isolate.in","r",stdin);//
freopen("isolate.out","w",stdout);
cin>>n;
cnt=1;
for(int i=1; i<=n; i++){
cin>>a[i];//输入每次所需的时间
if(a[i]>=240)flag=1;//如果有大于240(需要隔离的,就用flag标记一下
sum+=a[i];//统计所有办事时间和
}
if(flag==1){//如果有>240的
cout<<sum+10480;//直接一直呆在B,输出
return 0;//就不需要后面的判断了
}
for(int i=1;i<=n;i++)//进行模拟n次办事
if(now+a[i]>=240){//判断可不可以进行分组(一次干多件事),如果目前超过了
cnt++;//组数++
now=a[i];//之前的分组清空,新起一组
}else now+=a[i];//继续当前分组
cout<<min(cnt*400,10480)+sum;//判断是来回跑还是一直呆在B时间大
return 0;
}
T2和积
题目想法:
看到这道题,第一想法就是从M到N进行模拟(只能这样)因为是多测,所以在时间复杂度里还要乘上一个测试数据T。每次计算一个数的位数和和位数积需要复杂度一个常数10
所以时间复杂度为O(10NT)
这里面N和T都是不能优化的,只有常数可以优化。这里考虑使用记忆化,预处理每个数的位数和和位数积。优化后时间复杂度就是O(NT)
本题为多测!!!输出要换行!!!
PAC(赛时代码微改)
#include<bits/stdc++.h>//70分!为预处理!!!
using namespace std;
int S(int k) {
int sum=0;
while(k) {
sum+=k%10;
k/=10;
}
return sum;
}
int J(int R) {
int ans=1;
while(R) {
ans*=R%10;
R/=10;
}
return ans;
}
int main() {
freopen("sump.in","r",stdin);
freopen("sump.out","w",stdout);
int N,m,n,k,ans,cnt,mn;
cin>>N;
while(N--){
cin>>m>>n>>k;
ans=0,cnt=1,mn=-1;
for(int i=m; i<=n; i++)
if(S(i)==k&&J(i)> mn) {
mn=J(i);
ans=i;
}
cout<<ans<<" "<<mn<<endl;
}
return 0;
}
AC(稍微加了预处理)
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+10;
int a[N],b[N],T,m,n,k,ans,cnt,mn;
int S(int k) {
int sum=0;
while(k) sum+=k%10,k/=10;
return sum;
}
int J(int R) {
int ans=1;
while(R) ans=ans*(R%10),R/=10;
return ans;
}
void solve() {
cin>>m>>n>>k;
ans=0,cnt=1,mn=-1;
for(int i=m; i<=n; i++)//重复枚举每个n到m
if(a[i]==k&&b[i]> mn) {//如果满足条件切乘积和max,就替换
mn=b[i];
ans=i;//记录满足条件的i
}
cout<<ans<<" "<<mn<<endl;
return ;
}
int main() {
freopen("sump.in","r",stdin);
freopen("sump.out","w",stdout);
cin>>T;
for(int i=1; i<=5e6; i++) {//预处理每个数的乘积和位数和
a[i]=S(i);
b[i]=J(i);
}
while(T--) {//进行多组数据
solve();
}
return 0;
}
T3 电梯停靠
思路:
像解一个绝对值方程,使用零点分段法。
例: |x-5|+|x-7|
算当x<5、5<x<7,7<x(部分包含等于)
所以x点到各个上下车地点最小值就是最大最小点的中间值。(不然绝对会TLE
赛时代码:
纯模拟,(要么wa,要么tle)最后20分
#include<bits/stdc++.h>
using namespace std;
const int N=5*1e5+5;
int a[5][N];
int main() {
freopen("lift.in","r",stdin);
freopen("lift.out","w",stdout);
int n,m,bianhao=0,juli=N,ans;
cin>>n>>m;
for(int i=1; i<=m; i++) {
cin>>a[1][i]>>a[2][i];
}
for(int x=1; x<=n; x++,ans=0) {
for(int i=1; i<=m; i++) {
ans=ans+abs(x-a[1][i])+abs(a[1][i]-a[2][i])+abs(a[2][i]-x);
}
if(ans<juli) {
bianhao=x;
juli=ans;
}
}
cout<<bianhao<<" "<<juli;
return 0;
}
AC代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
int n,m,a[N],A[N],b[N],B[N];
int _abs(int x){
return x>0?x:-x;
}
signed main() {
freopen("lift.in","r",stdin);
freopen("lift.out","w",stdout);
cin>>n>>m;
int sum=0;
for(int i=1;i<=m;i++){
int x,y;
scanf("%lld %lld",&x,&y);
sum+=_abs(x-y)*2;
a[x-1]+=2,b[y+1]+=2;
}
for(int i=n;i>=1;i--){
a[i]+=a[i+1];
A[i]=A[i+1]+a[i];
}
int minn=1e18,idx;
for(int i=1;i<=n;i++){
b[i]+=b[i-1];
B[i]=B[i-1]+b[i];
int res=A[i]+B[i];
if(res<minn) minn=res,idx=i;
}
cout<<idx<<" "<<minn+sum;
return 0;
}
T4 分组选数
不会改!
总结:
本次模拟需要重视的细节很多,但大多数我没注意到。
在今后的比赛(模拟)中,要注意:
1,能多拿分就多拿分(争取前两题暴力模拟多得分,优化不重要(可能会错))后面的第四题,能A少数测试点,争取拿1~20分。
2,前面的题争取在前面时间内改完,不要遗留到后面
3,先读懂题在开始写,不要慌。