2022.9.17校内模拟赛解题报告
校内模拟赛解题报告
T1#
思路#
基本的思路就是纯模拟,但很明显会 TLE,所以考虑一下如何优化,我们可以提前处理一下走完一边指令后的坐标,然后直接用 k 来除以当前的指令长度然后给 xy 加上得数乘以一遍指令后 xy 的移动距离,然后直接再去模拟 k 对指令长度的取模的值就好了,指令最多只有 5000 个字母,不用担心会 TLE。
代码#
#include<bits/stdc++.h>
#define N 100100
using namespace std;
string s;
int n,len,chao;
int main()
{
freopen("sanae.in","r",stdin);
freopen("sanae.out","w",stdout);
cin>>s>>n;
len=s.size();
chao=n/len;
n=n%len;
int x=0,y=0,dx=0,dy=0;
for(int i=0;i<len;i++)
{
if(s[i]=='E')dx++;
else if(s[i]=='S')dy--;
else if(s[i]=='W')dx--;
else if(s[i]=='N')dy++;
}
x+=chao*dx;
y+=chao*dy;
for(int i=0;i<n;i++)
{
if(s[i]=='E')x++;
else if(s[i]=='S')y--;
else if(s[i]=='W')x--;
else if(s[i]=='N')y++;
}
cout<<x<<" "<<y<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}
T2#
思路#
首先我们需要把图存起来,然后跑最短路,但是这个最短路的 dis 数组里面不是用来存放花费,而是存放当前从 1 到 n 需要多少次帮助,也就是当前 k 的值,然后主函数二分 k 的值知道有一个可行的答案为止,具体注释看代码。
代码#
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 20010
using namespace std;
struct sb{int to,w,next;}e[N];//存放边
int n,p,k,head[N],cnt,dis[N],vis[N];//dis存放走到当前点需要用多少次帮助,vis标记是否找到最短路
void add(int x,int y,int z)//加边操作
{
e[++cnt].to=y;
e[cnt].next=head[x];
e[cnt].w=z;
head[x]=cnt;
}
int check(int x)//二分查找答案
{
memset(dis,INF,sizeof(dis));//重置dis数组
queue<int>q;
dis[1]=0;//起点不用走
q.push(1);//起点入列
while(!q.empty())//只要队列不空
{
int qwq=q.front();//qwq取出队头元素
q.pop();//弹出
vis[qwq]=0;
for(int i=head[qwq];i;i=e[i].next)//遍历每一个与之相连的边
{
int o;//o是大于当前点的边权的数量
if(e[i].w>x)//如果当前边大于x
o=dis[qwq]+1;//o的值就是上一点能存放的o的值加1
else//否则
o=dis[qwq];//o不变,等于上一个起点dis的值
if(o<dis[e[i].to])//如果o的值小于当前终点的dis
{
dis[e[i].to]=o;//替换
if(!vis[e[i].to])//如果当前的点没有在队列里
{
q.push(e[i].to);//入列
vis[e[i].to]=1;//打上标记
}
}
}
}
if(dis[n]<=k)return 1;//如果当前终点的需要帮助次数小于k就返回可行
else return 0;
}
int main()
{
cin>>n>>p>>k;
for(int i=1;i<=p;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,z);//存无向图
add(y,x,z);
}
int ans=-1;//ans存放答案,一开始假设不可以
int l=0,r=1e7;//二分答案
while(l<=r)
{
int mid=(r+l)>>1;
if(check(mid))//check检验答案是否可行
r=mid-1,ans=mid;
else l=mid+1;
}
cout<<ans<<endl;//输出答案
return 0;
}
T3#
思路#
明显的 dp 但我不会 。
考试的时候没想出来直接打了一个爆搜,然后就过了答案是 0 的点。。。
正解:用 f 数组来表示当到达 i 时所有人等待的最少的时间,j表示当前的 i 由哪个时刻转移而来,然后很容易推出状态转移方程:
把右边的拆开就是:
再加上一些小优化就可以 A 掉了,具体看代码。
代码#
#include<bits/stdc++.h>
#define N 4000010
using namespace std;
int n,m,mt,t;
int f[N],ti[N],sum[N];//f存放当i时刻的最少等待时间,ti存放每一个人等待的前缀和,sum存放每一个节点所有人时间和的前缀和
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)//枚举每一个人
{
cin>>t;
ti[t]++;//累加
sum[t]+=t;//累加当前所有人的时间
mt=max(t,mt);//取最大时间
}
for(int i=1;i<=mt+m;i++)//处理前缀和
ti[i]+=ti[i-1],sum[i]+=sum[i-1];
for(int i=1;i<=mt+m;i++)//枚举每一个时间
{
if(i>=m&&ti[i]==ti[i-m])//处理中间没有人的情况
{
f[i]=f[i-m];
continue;
}
f[i]=ti[i]*i-sum[i];//处理当前人都在等待的情况
for(int j=max(i-2*m+1,0);j<=i-m;j++)//遍历每一个能由j推出i的情况,注意此时间段摆渡车只能来回一次
f[i]=min(f[i],f[j]+(ti[i]-ti[j])*i-(sum[i]-sum[j]));//当前点的值更新为原来的值和由j转移过来的值的较小值
}
int ans=1e9;
for(int i=mt;i<=mt+m;i++)
ans=min(ans,f[i]);//求最小值
cout<<ans<<endl;//输出答案
return 0;//好习惯
}
作者: 北烛青澜
出处:https://www.cnblogs.com/Multitree/articles/16703288.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!