oldssoj2676B(环)
2015-08-27 11:46
190 查看
题目描述
JRY is the leader of a village. He has n lands, and there are n roads connecting them. There is at most one road connecting two lands and all lands are connected.Now, JRY wants to divided the n lands into k disjoint sets of equal size, satisfying that one can move between any two lands belonging to the same set passing only through lands frome this set.
Furthermore, he wants to know how many k(1≤k≤n) he can choose.
输入
There are multiple testcases, the sum of n is less then 106.For each test case, the first line contains one integer n(1≤n≤105).
The next line contains n integers, the i-th integer ai means that there is an edge between i and ai. It is guaranteed that the graph doesn't contain self loops and multiple edges.
输出
For each testcase print a single integer - the number of ways to choose the integer k.样例输入
62 3 4 5 6 162 4 2 3 4 3样例输出
43提示
HintCase 1 : $k$ = 1,2,3,6
Case 2: $k$ = 1,3,6
#include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int maxn=200005; struct data{ int v,next; }e[maxn*2]; int n,fst[maxn],huan[maxn],fa[maxn],tot,dep[maxn],sum[maxn],ans,Set,pres[maxn],num[maxn],cnt; bool vis[maxn]; inline int get(){ char c;while(!isdigit(c=getchar())); int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48; return v; } inline void add(int x,int y){ e[++cnt].v=y;e[cnt].next=fst[x],fst[x]=cnt; } inline void gethuan(int x){ for(int i=fst[x];i;i=e[i].next){ int y=e[i].v; if(fa[x]==y)continue; if(!dep[y]){ dep[y]=dep[x]+1; fa[y]=x; gethuan(y); } else if(dep[y]<dep[x]){ int t=x; while(t!=y){ huan[++tot]=t; vis[t]=1; t=fa[t]; } huan[++tot]=t;vis[t]=1; } } } inline void getsum(int x,int lim){ sum[x]=1; for(int i=fst[x];i;i=e[i].next){ int y=e[i].v; if(y!=lim && !vis[y]){ getsum(y,x); sum[x]+=sum[y]; } } } int main(){ while(scanf("%d",&n)==1){ memset(fst,0,sizeof(fst)); memset(e,0,sizeof(e)); memset(vis,0,sizeof(vis)); memset(sum,0,sizeof(sum)); memset(dep,0,sizeof(dep)); ans=2;tot=0;Set=0;cnt=0; for(int i=1;i<=n;++i){ int x=get();fa[i]=i; add(i,x);add(x,i); } dep[1]=1;gethuan(1); for(int i=1;i<=tot;++i)getsum(huan[i],huan[i]); for(int i=2;i<n;++i){ if(n%i)continue; int p=i,k=n/p;Set=0; memset(num,0,sizeof(num)); for(int j=1;j<=n;++j)if(!vis[j] && !(sum[j]%p))++Set; pres[0]=0; for(int j=1;j<=tot;++j){ //删掉环上huan【1】和huan【tot】的边 int q=huan[j]; pres[j]=(pres[j-1]+sum[q])%p; ++num[pres[j]]; } for(int j=1;j<=tot;++j)if(Set+num[pres[j]]==k){ //枚举环上的边 ++ans; break; } } printf("%d\n",ans); } return 0; }
思想:n个点,n条边,可以看成一棵树,树上有一个环,先找出环上点的子数能分成几份,之后就与环上点没什么关系了。再枚举环上的边,拉成一棵树,再算环上能分成几份,若是份数之和与k相等,++ans。
num[ res ]数组记录余数为res的数目。容易发现,环上那个末尾节点的num=0,并且枚举下一条边时,num都减去同一个数,不用处理,即只要num=num[末尾节点],余数为零,份数加1。
相关文章推荐
- Download pdf file from JAX-RS
- C++ Jsoncpp源代码编译与解析Json
- 安卓笔记
- iOS:NSBundle的具体介绍
- 如何使用Xmanager及VNC登录远程桌面
- 字符串组合问题(无重复)
- Ruby第三天作业
- php调用短信接口,php发送短信接口
- Google Earth For Javascript 谷歌地球删除所有标记
- kafka学习(三)--java开发(基于kafka0.8版本)
- 提供语义分析和分词服务
- IOS-笔记16(Animation)
- configure: error: cannot run /bin/sh ./config.sub解决办法
- 迭代模式
- 为什么要使用SLF4J而不是Log4J
- Microsoft Edge 浏览器开始支持webkit私有样式
- easyui 自定义校验使用ajax方式。
- ECharts实例开发学习笔记一
- Emacs编辑器之Python与Perl的IDE环境配置
- Google Earth For Javascript 谷歌地球添加标记