主页
搜索
最近更新
数据统计
申请密钥
系统公告
1
/
1
请查看完所有公告
【CF325C】Monsters and Diamonds
最后更新于 2025-07-31 13:43:45
作者
Cry_For_theMoon
分类
题解
题解
CF325C
复制 Markdown
查看原文
删除文章
更新内容
二合一傻逼题。没看到边权一定为正数,以为有 0 边搞 max 部分搞了半天... 事实上 min 部分感觉就是[这题](https://www.luogu.com.cn/problem/P1875)改一改,是一个 dij 基础题。 具体说就是我们设 $f(i)$ 是一只怪物 $i$ 能得到的最少钻石数量,然后转移就是枚举它的拆分方式,设得到怪物集合 $S$ 和 $n$ 颗钻石,那么取 $n+\sum_{j\in S}f(j)$ 的最小值。 只要倒着跑最短路就行,就是每次确定一个怪物的 $f$ 以后,枚举所有拆分方式包含它的拆分,如果它是该拆分最后一个确定 $f$ 的怪物,那么这个拆分的 $start$(就是输入里每组拆分的第一个数)就可以被更新了。 容易发现这样能顺便跑出 -1 的信息。 然后 max 就很傻逼了,我们先把那些为 -1 的点忽略掉来看。然后每种拆分方式都至少得到一颗钻石,所以就很有意思,就是你不能出现环,具体地就是如果 $a$ 拆到最后又来一只 $a$ 那就 -2 了。 这个时候你可以缩点在 dag 上跑一个 dp。我本来这样写的结果最后弃了() 考虑直接记忆化,搜到还在 dfs 栈中的点说明 -2,搜到已经明确答案是 -2 的点,也可以确定答案是 -2。否则,枚举所有拆分方式然后直接转移就行了。 ```cpp #include<bits/stdc++.h> #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define op(x) ((x&1)?x+1:x-1) #define odd(x) (x&1) #define even(x) (!odd(x)) #define lc(x) (x<<1) #define rc(x) (lc(x)|1) #define lowbit(x) (x&-x) #define Max(a,b) (a>b?a:b) #define Min(a,b) (a<b?a:b) #define next Cry_For_theMoon #define il inline #define pb(x) push_back(x) #define is(x) insert(x) #define sit set<int>::iterator #define mapit map<int,int>::iterator #define pi pair<int,int> #define ppi pair<int,pi> #define pp pair<pi,pi> #define fr first #define se second #define vit vector<int>::iterator #define mp(x,y) make_pair(x,y) typedef long long ll; typedef unsigned long long ull; typedef unsigned int uint; typedef double db; using namespace std; const int MAXN=1e5+10,INF=1e9,LIM=3.14e8; int m,n,l[MAXN],st[MAXN],cnt[MAXN],ins[MAXN]; map<int,int>occ[MAXN]; set<int>s1[MAXN],s2[MAXN]; int ans[MAXN][2]; vector<int>e1[MAXN],e2[MAXN],from[MAXN]; struct Node{ int u,dis; bool operator<(const Node& n2)const{return dis>n2.dis;} }; priority_queue<Node>q; int vis[MAXN],dis[MAXN]; queue<int>qu; void output(); int dfs(int u){ vis[u]=1; if(ans[u][0]==-1)return ans[u][1]=ans[u][0]=-1; ins[u]=1; for(int idx:from[u]){ //计划idx int ret=0,val,flag1=1,flag2=1; for(pi p:occ[idx]){ int v=p.fr,w=p.se; //w个v if(ans[v][0]==-1){flag1=0;continue;} if(ins[v]){flag2=0;continue;} val=vis[v]?ans[v][1]:dfs(v); if(val==-2){flag2=0;continue;} ret=Min(LIM,ret+1ll*w*val); } if(!flag1)continue; if(!flag2){ins[u]=0;return ans[u][1]=-2;} ret=min(LIM,ret+cnt[idx]); ans[u][1]=max(ans[u][1],ret); } ins[u]=0; return ans[u][1]; } int main(){ scanf("%d%d",&m,&n); rep(i,1,m){ int tmp;scanf("%d%d",&st[i],&l[i]); from[st[i]].pb(i); rep(j,1,l[i]){ scanf("%d",&tmp); if(tmp==-1)cnt[i]++; else{ occ[i][tmp]++; s1[tmp].is(i); } } } //calculate min rep(i,0,n)dis[i]=INF; rep(i,1,m){ if(occ[i].size()==0){ dis[st[i]]=min(dis[st[i]],cnt[i]); q.push(((Node){st[i],dis[st[i]]})); } } while(q.size()){ Node tmp=q.top();q.pop(); int u=tmp.u;if(vis[u])continue; vis[u]=1; for(int idx:s1[u]){ int v=st[idx],w=cnt[idx]; s2[idx].is(u); if(s2[idx].size()==occ[idx].size()){ int sum=0; for(auto p:occ[idx]){ sum=min((ll)LIM,sum+1ll*p.se*dis[p.fr]); } sum=min(LIM,sum+w); if(dis[v]>sum){ dis[v]=sum; q.push(((Node){v,dis[v]})); } } } } rep(i,1,n)if(dis[i]==INF)ans[i][0]=-1;else ans[i][0]=dis[i]; //calculate max memset(vis,0,sizeof vis); rep(i,1,n){ if(vis[i])continue; dfs(i); } output(); return 0; } void output(){ rep(i,1,n){ if(ans[i][0]==-1)printf("-1 -1\n"); else printf("%d %d\n",ans[i][0],ans[i][1]); } } ```
正在渲染内容...
点赞
1
收藏
0