あいさか たいがblogAisaka_Taiga的博客
//https://img2018.cnblogs.com/blog/1646268/201908/1646268-20190806114008215-138720377.jpg

2022.9.17校内模拟赛解题报告

2022.9.17校内模拟赛解题报告

校内模拟赛解题报告

T1#

思路#

基本的思路就是纯模拟,但很明显会 TLE,所以考虑一下如何优化,我们可以提前处理一下走完一边指令后的坐标,然后直接用 k 来除以当前的指令长度然后给 xy 加上得数乘以一遍指令后 xy 的移动距离,然后直接再去模拟 k 对指令长度的取模的值就好了,指令最多只有 5000 个字母,不用担心会 TLE。

代码#

Copy
#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 的值知道有一个可行的答案为止,具体注释看代码。

代码#

Copy
#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 由哪个时刻转移而来,然后很容易推出状态转移方程:

f[i]=min(f[i],f[j]+t[k]<=ijt[k])

把右边的拆开就是:

cnt[i]jsum[i]

再加上一些小优化就可以 A 掉了,具体看代码。

代码#

Copy
#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;//好习惯 }
posted @   北烛青澜  阅读(24)  评论(0编辑  收藏  举报
编辑推荐:
· 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框架的用法!
点击右上角即可分享
微信分享提示
目录