BZOJ 1093 [ZJOI2007]最大半连通子图
2015-08-24 10:47
411 查看
1093: [ZJOI2007]最大半连通子图
Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 1986 Solved: 802
[Submit][Status][Discuss]
Description
Input
第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。Output
应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.Sample Input
6 6 200706031 2
2 1
1 3
2 4
5 6
6 4
Sample Output
33
HINT
对于100%的数据, N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8。Source
题解:缩点dp。注意处理好大点间的重边。你问我写哪种dp?首推topo啊!记忆化什么的常数大的。。。(雾
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<stack> #include<queue> #include<cstring> #define PAU putchar(' ') #define ENT putchar('\n') #define MSE(a,b) memset(a,b,sizeof(a)) #define REN(x) for(ted*e=fch[x];e;e=e->nxt) #define REN2(x) for(ted*e=fch2[x];e;e=e->nxt) #define TIL(x) for(int i=1;i<=x;i++) #define ALL(x) for(int j=1;j<=x;j++) using namespace std; const int maxn=100000+10,maxm=1000000+10,inf=1e9; struct ted{int x,y;ted*nxt;}adj[maxm],adj2[maxm],*fch[maxn],*fch2[maxn],*ms=adj,*ms2=adj2; void add(int x,int y){*ms=(ted){x,y,fch[x]};fch[x]=ms++;return;}int in[maxn]; void add2(int x,int y){*ms2=(ted){x,y,fch2[x]};fch2[x]=ms2++;in[y]++;return;} int dfn[maxn],low[maxn],beg[maxn],siz[maxn],scc,cz,f[maxn],g[maxn],vis[maxn],mod;bool ins[maxn];stack<int>S; void tarjan(int x){ dfn[x]=low[x]=++cz;ins[x]=true;S.push(x);REN(x){int v=e->y; if(!dfn[v])tarjan(v),low[x]=min(low[x],low[v]);else if(ins[v])low[x]=min(low[x],dfn[v]); }if(low[x]==dfn[x]){scc++;int t; do beg[t=S.top()]=scc,ins[t]=false,S.pop(),siz[scc]++;while(t!=x); }return; } int n,m; void rebuild(){ TIL(n)REN(i)if(beg[i]!=beg[e->y])add2(beg[i],beg[e->y]);return; } void topodp(){ queue<int>Q;TIL(scc)if(!in[i])Q.push(i);TIL(scc)f[i]=siz[i],g[i]=1; while(!Q.empty()){ int x=Q.front();Q.pop();REN2(x){int v=e->y; if(--in[v]==0)Q.push(v); if(vis[v]!=x){vis[v]=x; if(f[x]+siz[v]>f[v])f[v]=f[x]+siz[v],g[v]=g[x]; else if(f[x]+siz[v]==f[v])(g[v]+=g[x])%=mod; } } }return; } inline int read(){ int x=0;bool sig=true;char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')sig=false; for(;isdigit(ch);ch=getchar())x=10*x+ch-'0';return sig?x:-x; } inline void write(int x){ if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x; int len=0;static int buf[20];while(x)buf[len++]=x%10,x/=10; for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return; } int main(){ n=read();m=read();mod=read();int x,y; TIL(m)x=read(),y=read(),add(x,y); TIL(n)if(!dfn[i])tarjan(i);rebuild();topodp(); int mx=-inf,ans; TIL(scc){ if(mx<f[i])mx=f[i],ans=g[i]; else if(f[i]==mx)(ans+=g[i])%=mod; }write(mx);ENT;write(ans); return 0; }
相关文章推荐
- Rhel 7 nfs install
- D3D显示YUV图像
- Java中莫名其妙的时区错误
- Android View 属性详解
- LINUX笔记6
- STM32窗口看门狗
- A1073. Scientific Notation (20)
- js思路总结
- Raising Modulo Numbers(poj 1995 快速幂)
- 阿里巴巴2016年秋季校园招聘C++研发岗在线笔试附加题第一题
- spark源码阅读环境搭建
- LINUX 笔记5
- (转)关于oracle的表空间,分区表,以及索引的总结
- 范围for语句
- pl/sql综合
- hdu1175 连连看(DFS+剪枝)
- ETL调度工具JobStream功能及源代码
- 访问单个节点的删除(Java)
- 链表分割
- V4包没注释,看不了源码解决方法(网上搜的,亲测可行)