UVa 11174 Stand in a Line

2024-06-19 15:32
文章标签 uva 11174 stand line

本文主要是介绍UVa 11174 Stand in a Line,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

      依旧是《训练指南》上的一道例题。书上讲的比较抽象,下面就把解法具体一下。因为涉及到父子关系,因此自然而然可以将n个节点构造成一棵树,最后将形成一个森林。接下来将使用递归的手法。设f(i)是以节点i为树根的子树,节点i有儿子c1,c2,c3....cj共j棵子树。s[i]为树根为i的子树包含的节点数。如果分别先给各个子树内部排序,那么毫无疑问,

共有f(c1)*f(c2)*f(c3)....*f(cj)种情况。接下来又要将所有子树的节点排成一个序列。那么我们事先不考虑各个子树的内部排序,共有(s[i]-1)!/(s[c1]!*s[c2]!*.....s[cj]!种情况。最后,我们将两种情况合起来,就是f(i)的解了,为f(c1)*f(c2)....*f(cj)*(s[i]-1)!/(s[c1]!*s[c2]!*.....s[cj]!)中情况。

        事实上,接下来还可以进一步化简,设c1有孩子节点x1,x2,x3....xk。那么f(c1)=f(x1)*f(x2).....f(xk)*(s[c1]-1)!/(s[x1]!*x[x2]!....*x[xk]!)。将f(c1)代入,分子中的(s[c1]-1)!和分母中的s[c1]!约分的s[c1],然后依次类推,最后分母必然会化为s[1]*s[2]*s[3]...s[n]。因为总共n个节点构成一个森林,因此s[root](root可能为虚拟树根)为n+1,那么最后分母为n!。最后,求出n!/(s[1]*s[2]...s[n])就是我们要求的解。

       还要注意的是,最后模运算的时候,1的逆为1。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#define MAX 40000+5
#define MOD 1000000007
#define LL long long
using namespace std;LL fac[MAX],N[MAX];//fac[i]为i!,N[i]为i关于MOD的逆
int T,n,m;
int s[MAX],vis[MAX];
vector<int> Tree[MAX];LL inv(LL a,LL n);
void gcd(LL a,LL b,LL& d,LL& x,LL& y);
int dfs(int);int main()
{freopen("data.txt","r",stdin);fac[0]=fac[1]=N[1]=1;//注意1的逆为1for(LL i=2;i<MAX;++i){fac[i]=(i*fac[i-1])%MOD;N[i]=inv(i,MOD);}cin>>T;while(T--){cin>>n>>m;memset(vis,0,sizeof(vis));for(int i=1;i<=n;++i) Tree[i].clear();for(int i=0;i<m;++i){int a,b;cin>>a>>b;Tree[b].push_back(a);}for(int i=1;i<=n;++i){//DFS统计每棵子树包含的节点数if(!vis[i]) dfs(i);}LL ans=fac[n];for(int i=1;i<=n;++i){ans=(ans*N[s[i]])%MOD;}cout<<ans<<endl;}return 0;
}LL inv(LL a,LL n)//求逆运算,参考《训练指南》
{LL d,x,y;gcd(a,n,d,x,y);return d==1?(x+n)%n:-1;
}void gcd(LL a,LL b,LL& d,LL& x,LL& y)//扩展欧几里得算法
{if(!b){d=a;x=1;y=0;}else{gcd(b,a%b,d,y,x);y-=x*(a/b);}
}int dfs(int r)
{int num=0;for(int i=0;i<Tree[r].size();++i){num+=dfs(Tree[r][i]);}vis[r]=1;s[r]=num+1;return s[r];
}


这篇关于UVa 11174 Stand in a Line的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1075423

相关文章

UVA - 12206 Stammering Aliens (hash)

这题其实很容易想到2分长度,关键是2分后,怎么判断出现最多次的串是否》=m次了。这里需要用到hash来处理。 对于一个字符串   H[i] =H[i+1]*131+s[i]  ;其中 H[n]=0;那么对于一个长度为L的串 ,hanh[i,l]=H[i]-H[i+L]*x^L ; 这样记录每个字符串的hash值,然后再处理起来就比较简单了。 VIEW CODE #include<

「Debug R」如何处理Error in readLines(f) :(converted from warning) incomplete final line found on xxx...

用devtools::install_github从GitHub上安装一个R包的时候出现了报错, 报错截图如下所示: 报错 从报错内容基本上可以确定是换行符惹的祸,我将该文件传送到Linux下,用cat -A检查,发现最后一行后面没有换行符。 ^M是Windows的换行符 解决方案: 手动增加最后一行。 手动加换行 到此当前的

[Uva 11990] Dynamic Inversion (CDQ分治入门)

Uva - 11990 动态逆序对,求删除一个点之前序列中逆序对的个数 首先倒过来看这个问题,把点先全部删掉 然后从最后一个点开始倒着往数列中加点 求加完这个点逆序对的变化 CDQ分治做法 把删除时间看作 t,下标看作 x,值看作 y 然后对 x排序,对 t偏序,用树状数组维护 y 具体来说就是对于每个点 (t0,x0,y0) (t_0, x_0, y_0) 先统计

configparser.DuplicateSectionError: While reading from '/home/qinghua/.theanorc' [line 18]: section

python代码: import theano 出现错误: configparser.DuplicateSectionError: While reading from '/home/qinghua/.theanorc' [line 18]: section 'nvcc' already exists 解决方法是, vim ~/.theeanorc 删除行: [nvcc]

UVA 11624 搜索

给出1000*1000矩阵,含起点‘J’,路‘.',墙‘#’,火‘F'; 火每秒蔓延一格,人每秒走一步 问人是否可以安全走出矩阵,不能被火碰到 先对所有火BFS一遍,记录每个点被烧到的时间 然后对人BFS一遍,若到每点前没被火烧即可走 #include "stdio.h"#include "string.h"#include "queue"using namespace

line-height:150%与line-height:1.5的区别

这是一个小小的不经意的问题,但是却常常被一些面试官提起。一般都会一下子进入懵逼状态,那让我们来看看区别在哪里? 我先新建一个html,代码如下: <div style="line-height:150%;font-size:16px;">父元素内容<div style="font-size:30px;">Web前端开发<br/>line-height行高问题</div></div>

UVa 11361 Investigating Div-Sum Property

这道题居然提交了十次才过....期间小问题不断。思路的话基本是《训练指南》里面来的,不过有几个小问题需要注意一下。第一,当K在大于100的情况下,就直接输出0就可以了。因为a,b不超过2^31,可以估算出a,b最多十位十进制数,那么每位最大为9,所以各个数字之和是不可能超过100的,那么个数字之和为模K为0的条件是永远不可能到达的。       还有一点是,当剩余数字d=0时,当且

UVa 1362(LA 3516) Exploring Pyramids

依旧是《训练指南》上的一道例题。思路大致相同,即设有一个序列S(i),S(i+1),S(i+2)...S(j),d[i,j]为所求的解。当S(i)==S(k),i<k<=j 时,说明在k回到根,那么S(i+1)...S(k-1)构成一棵独立的子树(当然也可能并不是子树)。那么d[i,j]就要加上d[i+1,k-1]*d[k,j],不断递增k,每遇到一个k,d[i,j]+=d[i

UVa 11375 Matches

大年夜的写代码果然状态非常之差...感觉特别困,连个高精度都折腾了我好久。还是刘汝佳《训练指南》里的一道例题,解题思路其实也差不多,但是想对书里面的内容再讲讲。其中d[i]是代表i个火柴棒恰好能构成的正整数数目(不包含整数0),然后有点类似于动态规划的做法,通过已知的d[]求出剩下的d[]。        不过仔细想来貌似有点问题。例如已知d[j],那么d[j+num[0]]+=d[

UVa CD 0-1背包且打印路径

就是简单的0-1背包问题,不过没有具体的效益值,隐含的效益值就是剩余背包的容量。因为要输出具体选择了那些track(也就是物品),所以采用序偶的方法。其实0-1背包的解画在坐标轴上就是一个分段函数,所谓序偶就是那些跃迁的节点。但是这道题略有不同,第0阶段的初始序偶不是(0,0),而是(0,N)。序偶的第一个参数表示容量,第二个参数表示背包的剩余容量。当由前一阶段的序偶得到新序偶,并且