修仙录 3.15

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41709770/article/details/88584696

怎么又是些毒瘤题

确实被恶心到了


jzoj 6059 Tried

https://jzoj.net/senior/#main/show/6059
其实就是找最长路径,但是细节简直多到吐
搞得我自己打的dp,每个子任务都错一个,结果又是0分QAQ
但是用topsort+逐层贪心好像避免了很多特判
题解大法好
题解:
若图中存在一条非 0 边可以到达任意一个环,我们可以直接输出
两个 inf,否则我们可以将 0 环给缩成一个点,方案数记为 inf。
于是只要考虑图是一个有向无环图时的情况。
接下来我们可以求出每个点向下得到的最大位数,随后逐位确定
即可,。

多说无益,直接上浓缩了精力与心血的代码
QAQ

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int MAXN=1e5+5;
const int MAXM=1e6+5;
const int mod=998244353;

int n,m;
struct grath{
	int head[MAXN],next[MAXM*2],to[MAXM*2],w[MAXM*2],du[MAXN],cnt;
	int ml[MAXN][2],f[MAXN];
	bool p[MAXN];
	void add(int u,int v,int l){
		next[++cnt]=head[u],to[cnt]=v,w[cnt]=l,du[v]++,head[u]=cnt;
	}
}A,B,C;
int dfn[MAXN],low[MAXN],tot,stack[MAXN],top,isn[MAXN];
int h[MAXN],sh,w[MAXN];
int mx,sum;

void tarjan(int x){
	dfn[x]=low[x]=++tot,stack[++top]=x,isn[x]=1;
	for(int i=A.head[x];i;i=A.next[i]){
		int y=A.to[i];
		if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);
		else if(isn[y]) low[x]=min(low[x],dfn[y]);
	}
	if(dfn[x]==low[x]){
		sh++;
		while(1){
			int t=stack[top--];
			h[t]=sh,isn[t]=0;
			if(t==x) break;
		}
	}
}

int Plus(int x,int y){
	if(x<0||y<0) return -1;
	return (x+y)%mod;
}

queue<int>q;
void topsort(grath &A){
	for(int i=1;i<=sh;i++){
		if(!A.du[i]) q.push(i);
		A.f[i]= w[i]>=0?-1:1;
	}
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=A.head[x];i;i=A.next[i]){
			int y=A.to[i],w=A.w[i]; A.du[y]--;
			if(!A.du[y]) q.push(y);
			A.p[y]|=A.p[x];
			A.ml[y][w>0]=max(A.ml[y][w>0],max(A.ml[x][0],A.ml[x][1])+1);
			A.f[y]=Plus(A.f[x],A.f[y]);
		}
	}
}

vector<int>t[MAXN];
bool isv[MAXN];

int main(){
	freopen("tried.in","r",stdin);
	freopen("tried.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v,l;scanf("%d%d%d",&u,&v,&l);
		A.add(u,v,l);
	}
	for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
	memset(w,-1,sizeof(w));
	for(int x=1;x<=n;x++) for(int i=A.head[x];i;i=A.next[i]){
		int y=A.to[i],l=A.w[i];
		if(h[x]!=h[y]) B.add(h[x],h[y],l),C.add(h[y],h[x],l);
		else w[h[x]]=max(w[h[x]],l);
	}
	for(int i=1;i<=sh;i++) if(w[i]>0) {printf("inf\ninf");return 0;}
	for(int i=1;i<=sh;i++) if(w[i]==0) B.p[i]=C.p[i]=1;
	topsort(B);
	for(int x=1;x<=sh;x++)
		if(B.p[x]) for(int i=B.head[x];i;i=B.next[i])
			if(B.w[i]) {printf("inf\ninf");return 0;}
	topsort(C);
	for(int i=1;i<=sh;i++) mx=max(mx,B.ml[i][1]);
	if(!mx){
		for(int i=1;i<=sh;i++) sum=Plus(sum,C.f[i]);
		printf("0\n");
		if(sum<0) printf("inf");
		else printf("%d",sum);
		return 0;
	}
	for(int i=1;i<=sh;i++)
		if(B.ml[i][1]==mx) t[mx].push_back(i),isv[i]=1;
		else{
			int o=max(B.ml[i][0],B.ml[i][1]);
			if(o<mx) t[o].push_back(i);
			C.f[i]=0;
		}
	for(int k=mx;k;k--){
		int o=0;
		for(int j=0;j<t[k].size();j++){
			int x=t[k][j];
			if(!isv[x]) continue;
			for(int i=C.head[x];i;i=C.next[i]){
				int y=C.to[i];
				if(max(B.ml[y][0],B.ml[y][1])==k-1) o=max(o,C.w[i]);
			}
		}
		for(int j=0;j<t[k].size();j++){
			int x=t[k][j];
			if(!isv[x]) continue;
			for(int i=C.head[x];i;i=C.next[i]){
				int y=C.to[i];
				if(max(B.ml[y][0],B.ml[y][1])==k-1&&o==C.w[i]) C.f[y]=Plus(C.f[y],C.f[x]),isv[y]=1;
			}
		}
		printf("%d",o);
	}
	printf("\n");
	for(int i=0;i<t[0].size();i++) if(isv[t[0][i]]) sum=Plus(sum,C.f[t[0][i]]);
	if(sum<0) printf("inf");
	else printf("%d",sum);
	return 0;
} 

第二题又是神奇操作:话说是怎么又把四个 \sum 变成四元环的。
第三题好像还能搞。

猜你喜欢

转载自blog.csdn.net/qq_41709770/article/details/88584696
今日推荐