ABC334 F&G
F:
我们可以更好的利用一操作——当且仅当钱不够用时,加上经过的所有点中最大的
设
转移时,先枚举
正确性显然。因为我们是在钱不够用时才操作,所以对于任意
具体
#include<algorithm>
#include<cstdio>
#include<cstring>
#define pii pair<int,int>
#define mk make_pair
#define ft first
#define se second
#define pb push_back
#define db double
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define inf 1e18
using namespace std;
namespace IO{
#ifndef LOCAL
#define SIZE 30000
char in[SIZE],out[SIZE],*p1=in,*p2=in,*p3=out;
#define getchar() (p1==p2&&(p2=(p1=in)+fread(in,1,SIZE,stdin),p1==p2)?EOF:*p1++)
#define flush() (fwrite(p3=out,1,SIZE,stdout))
#define putchar(ch) (p3==out+SIZE&&flush(),*p3++=(ch))
class Flush{public:~Flush(){fwrite(out,1,p3-out,stdout);}}_;
#endif
template<typename type>
inline void read(type &x){
x=0;bool flag=0;char ch=getchar();
while(ch<'0'||ch>'9') flag^=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
flag?x=-x:0;
}
template<typename type>
inline void write(type x,char ch=0){
x<0?x=-x,putchar('-'):0;static short Stack[50],top=0;
do Stack[++top]=x%10,x/=10;while(x);
while(top) putchar(Stack[top--]|48);
if(ch) putchar(ch);
}
}
using namespace IO;
#define M 85
int n,p[M][M],r[M][M],d[M][M];
pair<ll,ll> dp[M][M][M][M];
int main(){
read(n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
read(p[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<n;j++){
read(r[i][j]);
}
}
for(int i=1;i<n;i++){
for(int j=1;j<=n;j++){
read(d[i][j]);
}
}
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){
for(int x=1;x<=n;x++) for(int y=1;y<=n;y++){
dp[i][j][x][y]=mk(inf,inf);
}
}
dp[1][1][1][1]=mk(0,0);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){
for(int x=1;x<=i;x++) for(int y=1;y<=j;y++){
if(dp[i][j][x][y].ft>1e14) continue;
if(i+1<=n){
ll need=dp[i][j][x][y].se+d[i][j],opr=0;
if(need>0){
opr=(need+p[x][y]-1)/p[x][y];
need-=opr*p[x][y];
}
int nx=x,ny=y;
if(p[i+1][j]>p[nx][ny]) nx=i+1,ny=j;
dp[i+1][j][nx][ny]=min(dp[i+1][j][nx][ny],mk(dp[i][j][x][y].ft+opr,need));
}
if(j+1<=n){
ll need=dp[i][j][x][y].se+r[i][j],opr=0;
if(need>0){
opr=(need+p[x][y]-1)/p[x][y];
need-=opr*p[x][y];
}
int nx=x,ny=y;
if(p[i][j+1]>p[nx][ny]) nx=i,ny=j+1;
dp[i][j+1][nx][ny]=min(dp[i][j+1][nx][ny],mk(dp[i][j][x][y].ft+opr,need));
}
}
}
ll ans=inf;
for(int x=1;x<=n;x++){
for(int y=1;y<=n;y++){
ans=min(ans,dp[n][n][x][y].ft);
}
}
write(ans+2*(n-1),'\n');
return 0;
}
G:
官方题解给出了一种巧妙的做法。下面再提一提。
由
不妨将询问按
初始情况可以视作
将
具体地,对于
接下来,只要考虑每次回答询问前完成为数不多(
下面是具体实现:
开始时,把所有交换点放进优先队列,堆顶为最小的交换点。
每次询问前,若堆顶值小于当前的
特别注意,堆顶值对应的两条直线此时可能已经不相邻,若如此应忽略这个值并将其弹出。
一个简单二分回答询问即可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】