题解 P13271 [NOI2025] 机器人
铁牌选手凑个热闹,这也是 NOI.jpg
Solution
观察到对于每个点,有效的 \(p\) 只有 \(d_i\) 个,这样状态总数就是 \(\sum d_i=m\)。
考虑拆点,每个点拆成 \(d_i\) 个点表示它的所有 \(p\) 的状态。单个点的状态之间通过 \(v\) 和 \(w\) 建边。在处理原图的边的时候如果 \(v\) 的状态不足这条边的 \(p\),连到 \(v\) 的最大编号,简单计算边权即可。最后跑一个最短路就做完了。
由于还要建立一个点计算实际的最短路,总点数是 \(N=n+m\),总边数是 \(M=2m+m=3m\),时间复杂度就是 \(O(M\log M)\)。
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf=1e18;
const int N=3e5+10;
int n,m,k;
int tot;
int d[N];
struct node{
int v;
ll w;
friend bool operator<(node x,node y){
return x.w>y.w;
}
};
vector<node>g[N*2];
vector<int>num[N];
int U[N],V[N],ID[N],cnt;
ll W[N];
int w1[N],w2[N];
ll sum[N];
void add(int u,int v,ll w){
g[u].push_back({v,w});
}
ll dis[N];
void dij(int s){
for(int i=1;i<=tot;i++){
dis[i]=inf;
}
priority_queue<node>q;
q.push({s,0});
dis[s]=0;
while(!q.empty()){
node tmp=q.top();
q.pop();
int x=tmp.v;
if(tmp.w>dis[x]){
continue;
}
for(auto i:g[x]){
int v=i.v;
ll w=i.w;
if(dis[v]>dis[x]+w){
dis[v]=dis[x]+w;
q.push({v,dis[v]});
}
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int c;
cin>>c>>n>>m>>k;
for(int i=1;i<k;i++){
cin>>w1[i];
}
for(int i=2;i<=k;i++){
cin>>w2[i];
sum[i]=sum[i-1]+w2[i];
}
for(int i=1;i<=n;i++){
cin>>d[i];
num[i].resize(d[i]+1);
num[i][0]=++tot;
for(int j=1;j<=d[i];j++){
num[i][j]=++tot;
++cnt;
U[cnt]=i;
ID[cnt]=j;
cin>>V[cnt]>>W[cnt];
}
for(int j=1;j<=d[i];j++){
if(j<d[i]){
add(num[i][j],num[i][j+1],w1[j]);
}
if(j>1){
add(num[i][j],num[i][j-1],w2[j]);
}
}
}
for(int i=1;i<=m;i++){
int u=U[i],v=V[i],id=ID[i];
ll w=W[i];
add(num[u][id],num[v][0],w);
if(id>d[v]){
add(num[u][id],num[v][d[v]],w+sum[id]-sum[d[v]]);
}else{
add(num[u][id],num[v][id],w);
}
}
if(!d[1]){
cout<<"0 ";
for(int i=1;i<=n;i++){
cout<<"-1 ";
}
cout<<'\n';
return 0;
}
dij(num[1][1]);
cout<<"0 ";
for(int i=2;i<=n;i++){
ll ans=dis[num[i][0]];
if(ans>1e17){
cout<<"-1 ";
}else{
cout<<ans<<' ';
}
}
cout<<'\n';
return 0;
}
一些闲话
赛时不到 1h 即想出了正解,但是因为谜之原因(可能是太困了)导致我认为状态总数是 \(O(k^2)\),进而导致我转向别的思路并成功没场切绿题打铁呜呜。

浙公网安备 33010602011771号