JOI 2021 Final
链接
B. Snowball
显然每个雪球不可能在越过其他雪球获得雪。对于每个雪球求出其左右两边覆盖的长度,具体求法可以直接二分然后判断两端到达这个位置的时间,以此判断这个位置被谁覆盖。
复杂度 。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 200010
#define ll long long
using namespace std;
ll s[N],p[N],ft[N],gt[N],ans[N];
const ll inf=1e18;
int main()
{
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&p[i]);
for(int i=1;i<=m;i++) scanf("%lld",&s[i]),s[i]+=s[i-1];
for(int i=1;i<=m;i++) ft[i]=max(s[i],ft[i-1]),gt[i]=max(-s[i],gt[i-1]);
p[0]=-inf,p[n+1]=inf;
for(int i=0;i<=n;i++)
{
ll d=p[i+1]-p[i];
if(d>=ft[m]+gt[m]){ans[i]+=ft[m],ans[i+1]+=gt[m];continue;}
int l=1,r=m,res=1;
while(l<=r)
{
int mid=(l+r)>>1;
if(ft[mid]+gt[mid]>d) r=mid-1,res=mid;
else l=mid+1;
}
if(gt[res]!=gt[res-1]) ans[i+1]+=d-ft[res],ans[i]+=ft[res];
else ans[i+1]+=gt[res],ans[i]+=d-gt[res];
}
for(int i=1;i<=n;i++) printf("%lld\n",ans[i]);
return 0;
}
C. Group Photo
由于身高是一个排列,容易发现最后形成的一定是若干 4321|654|987
这样若干连续下降段构成的上升序列。
考虑 dp。设 表示将 放置在前 个位置,最后一个是 的合法方案。通过 也可以知道 的位置。由于前 个数已经确定,可以推出 的当前位置。对于当前 可以:移到 的右边,或者单独开一条链。分别处理贡献即可。
复杂度 。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 5010
using namespace std;
int a[N],p[N],f[N],g[N][N];const int inf=1e9;
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),p[a[i]]=i;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) g[i][j]=g[i-1][j]+(a[i]<=j);
for(int i=1;i<=n;i++) f[i]=inf;
f[0]=0;
for(int i=1;i<=n;i++)
for(int j=i,s=0;j;j--)
s+=(i-j)+(g[p[j]][n]-g[p[j]][i])-(g[p[j]][i]-g[p[j]][j]),f[i]=min(f[i],f[j-1]+s);
printf("%d\n",f[n]);
return 0;
}
D. Robot
由于可选颜色范围 ,一定存在一种方案使得修改后的边与其他所有边颜色不同。假设现在在 ,要经过边 ,要么修改与 相连的边所有颜色为 的边,要么修改当前边的颜色。
但是注意到我们无法记录当前点是从哪里来的,可能会出现重复修改某条边的情况。不妨对每个点的每个颜色新建一个点,走到这个点不需要代价,因为走到这个点表示接下来要走相同颜色的边,所以这条边会在走出去的时候计算贡献。这样就避免重复贡献。
跑最短路。复杂度 。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#define N 400010
#define fi first
#define se second
using namespace std;
typedef long long ll;
map<int,vector<pair<int,int>>>g[N];
int nxt[N<<2],to[N<<2],head[N],cnt;ll w[N<<2];
void add(int u,int v,ll w0){nxt[++cnt]=head[u];to[cnt]=v;w[cnt]=w0;head[u]=cnt;}
ll dis[N];bool vis[N];priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<pair<ll,int>>>q;
ll dij(int s,int t)
{
memset(dis,0x3f,sizeof(dis));
dis[s]=0,q.push({0,s});
while(!q.empty())
{
int u=q.top().se;q.pop();
if(vis[u]) continue;vis[u]=true;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];if(dis[v]<=dis[u]+w[i]) continue;
dis[v]=dis[u]+w[i],q.push({dis[v],v});
}
}
return dis[t];
}
int main()
{
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,c,p;scanf("%d%d%d%d",&u,&v,&c,&p);
g[u][c].push_back({v,p}),g[v][c].push_back({u,p});
}
int tt=n;
for(int u=1;u<=n;u++)
for(auto [c,p]:g[u])
{
// cerr<<"in: "<<u<<" "<<c<<endl;
ll res=0;for(auto a:p) res+=a.se;
for(auto [v,w]:p) add(u,v,min((ll)w,res-w));
if(p.size()<=1) continue;
++tt;
for(auto [v,w]:p) add(v,tt,0),add(tt,v,res-w);
}
ll ans=dij(1,n);
printf("%lld\n",ans>1e18?-1ll:ans);
return 0;
}
E. Dungeon 3
本文来自博客园,作者:Flying2018,转载请注明原文链接:https://www.cnblogs.com/Flying2018/p/16096126.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理