• [ZJOI2007]最大半连通子图


    题目

    BZOJ

    做法

    弱联通子图,也就是本题的半联通子图
    烂大街的概念:一个弱联通子图,一定是缩点后形成一条单直链
    至此,我们将本题转化为(DAG)图上(dp)题,打完惊奇地发现(WA)

    本题坑点:(DAG)图上要去重操作,反正方案重复统计

    My complete code

    #include<bits/stdc++.h>
    #include<vector>
    #include<queue>
    #include<map>
    using namespace std;
    typedef int LL;
    const LL maxn=1e6;
    struct node{
    	LL to,nxt;
    }dis[maxn];
    LL num,tim,top,cnt,ansk,ansn,n,m,p;
    LL head[maxn],dfn[maxn],low[maxn],du[maxn],sta[maxn],size[maxn],col[maxn],dp[maxn],sum[maxn];
    bool visit[maxn];
    inline void Add(LL u,LL v){
    	dis[++num]=(node){v,head[u]}, head[u]=num;
    }
    void Tarjan(LL u){
    	dfn[u]=low[u]=++tim; sta[++top]=u; visit[u]=true;
    	for(LL i=head[u];i;i=dis[i].nxt){
    		LL v(dis[i].to);
    		if(!dfn[v]){
    			Tarjan(v);
    			low[u]=min(low[u],low[v]);
    		}else if(visit[v]) low[u]=min(low[u],low[v]);
    	}
    	if(dfn[u]==low[u]){
    		LL now; ++cnt;
    		do{
    			now=sta[top--];
    			col[now]=cnt;
    			visit[now]=false;
    			++size[cnt];
    		}while(now!=u);
    	}
    }
    vector<LL> e[maxn];
    inline void Solve(){
    	queue<LL> que;
    	for(LL i=1;i<=cnt;++i) 
    	    if(!du[i])
    		    que.push(i),dp[i]=size[i],sum[i]=1%p;
    	while(que.size()){
    		LL u(que.front()); que.pop();
    		if(dp[u]>ansk){
    			ansk=dp[u];
    			ansn=sum[u];
    		}else if(dp[u]==ansk) (ansn+=sum[u])%=p;
    		for(LL i=0;i<e[u].size();++i){
    			LL v(e[u][i]);
    			if(!du[v]) continue;
    			if(dp[u]+size[v]>dp[v]){
    				dp[v]=dp[u]+size[v];
    				sum[v]=sum[u];
    			}else if(dp[u]+size[v]==dp[v])
    			    (sum[v]+=sum[u])%=p;
    			--du[v];
    			if(!du[v]) que.push(v);
    		}
    	}
    }
    struct E{
    	LL u,v;
    	bool operator < (const E &b)const{
    		return (u^b.u)?u<b.u:v<b.v;
    	}
    }a[maxn];
    int main(){
    	cin>>n>>m>>p;
    	for(LL i=1;i<=m;++i){
    		LL u,v; cin>>u>>v;
    		Add(u,v);
    	}
    	for(LL i=1;i<=n;++i)
    	    if(!dfn[i])
    	        Tarjan(i);
    	num=0;
    	for(LL u=1;u<=n;++u)
    		for(LL i=head[u];i;i=dis[i].nxt){
    			LL v(dis[i].to);
    			if(col[v]!=col[u])
    				a[++num]=(E){col[u],col[v]};
    		}
    	sort(a+1,a+1+num);
    	a[0]=(E){-1,-1};
    	for(LL i=1;i<=num;++i)
    	    if(a[i].u!=a[i-1].u || a[i].v!=a[i-1].v)
    	        e[a[i].u].push_back(a[i].v), ++du[a[i].v];
    	Solve();
    	cout<<ansk<<endl<<ansn;
    	return 0;
    }
    
  • 相关阅读:
    ORACLE 按照指定顺序排序输出某些字段
    jsp 选择年份产生周下拉框
    jsp标签foreach
    润乾报表个人笔记
    eclipse加大服务器容器内存
    jsp input中使用fmt 格式化时间
    log4j简单使用java web项目--后台打印以及输出到文件
    log4j简单使用java项目--后台打印以及输出到文件
    声明:放弃博客园平台,近日将所有随笔转移到CSDN,并删除所有已公开的随笔。
    项目 Java 2 go的一些准备活动
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10470213.html
Copyright © 2020-2023  润新知