zoukankan      html  css  js  c++  java
  • [BZOJ5219]最长路径

    Description

    在Byteland一共有n个城市,编号依次为1到n,它们之间计划修建n(n-1)/2条单向道路,对于任意两个不同的点i和
    j,在它们之间有且仅有一条单向道路,方向要么是i到j,要么是j到i。换句话说,这是一个n个点的竞赛图。Byte
    asar居住在1号城市,他希望从1号城市出发,沿着单向道路不重复地访问一些城市,使得访问的城市数尽可能多。
    请写一个程序,帮助Byteasar计算有多少种道路修建方式,使得从1号点出发的最长简单路径经过点数恰好为k,由
    于答案可能很大,请对P取模输出

    Input

    第一行包含两个正整数n,P,表示点数和模数。
    2≤P≤1e9,N<=2000

    Output

    输出n行,第i行输出从1出发的最长简单路径经过点数恰好为i的竞赛图个数模P。

    Sample Input

    2 233

    Sample Output

    1
    1


    题解

    计数题我永远都写不出来

    先扯点竞赛图的前置知识

    1.竞赛图就是有向完全图,有(C_{2}^{n})条有向边
    2.竞赛图经过缩点后一定是一条链,拓扑序小的连向所有拓扑序比ta大的节点
    3.竞赛图是一个哈密顿回路,竞赛图在缩点后是一个哈密顿路径
    4.竞赛图要不就是没有一个环的(DAG),要不就是每个强连通分量的点的个数至少为3,且每个强连通分量都有至少一个三元环

    由于竞赛图缩点以后一定是一条链
    所以从(1)开始的路径长度就是(1)所在的(scc)大小+拓扑序在(i)所在的(scc)后面的点的个数
    我们设(g_i)表示(i)个点的竞赛图个数
    (f_i)表示一个大小为(i)的是一个强连通分量的竞赛图的个数
    那么显然(g_n=2^{C_{2}^{n}})
    然后我们考虑怎么求(f_i)
    其实直接容斥就行了
    就枚举一个大小为(j[j<i])的强连通分量竞赛图
    然后剩下的(i-j)个点就不在这个强连通分量里
    所以这两者之间的边的方向是一定的
    (f_i=sum_{j=1}^{i-1}{C_{i}^{j}f_jg_{i-j}})
    然后我们就枚举(1)所在(scc)大小(i),再枚举拓扑序大于(1)所在的(scc)的点的个数(j)
    (ans[i+j]=C_{n-1}^{i} imes C_{j}^{n-i}f_ig_jg_{n-i-j})

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    const int M = 2005 ;
    using namespace std ;
    
    int n , mod ;
    int f[M] , g[M] , ans[M] , C[M][M] ;// f[i]表示一个联通块, g[i]表示i个点随便连
    inline int Fpw(int Base , int k) {
    	int temp = 1 ;
    	while(k) {
    		if(k & 1) temp = 1LL * temp * Base % mod ;
    		Base = 1LL * Base * Base % mod ; k >>= 1 ;
    	} 
    	return temp ;
    } 
    int main() {
    	scanf("%d%d",&n,&mod) ;
    	for(int i = 0 ; i <= n ; i ++) {
    		C[i][0] = 1 ;
    		for(int j = 1 ; j <= i ; j ++)
    			C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod ;
    	}
    	for(int i = 0 ; i <= n ; i ++) 
    		g[i] = Fpw(2 , C[i][2]) ;
    	for(int i = 1 ; i <= n ; i ++) {
    		f[i] = g[i] ;
    		for(int j = 1 ; j < i ; j ++) {
    			f[i] = (f[i] - 1LL * C[i][j] * f[j] % mod * g[i - j] % mod) % mod ;
    			f[i] = (f[i] + mod) % mod ;
    		}
    	}
    	for(int i = 1 ; i <= n ; i ++)
    		for(int j = 0 ; i + j <= n ; j ++)
    			ans[i + j] = (ans[i + j] + 1LL * C[n - 1][i - 1] * C[n - i][j] % mod * f[i] % mod * g[j] % mod * g[n - i - j] % mod) % mod ;
    	for(int i = 1 ; i <= n ; i ++) printf("%d
    ",ans[i]) ;
    	return 0 ;
    }
    
  • 相关阅读:
    介绍一些好用的ArcToolbox工具(默认ArcGIS没有)
    我的技术博客开始啦
    Qualcomm和MTK两个android平台比较
    kali安装nessus
    ImportError: cannot import name pxssh
    python 批量下载文件
    GitHub如何修改用户名
    Sass中使用@each循环
    PhpStorm 实用快捷键
    GitHub如何删除一个repository(仓库)
  • 原文地址:https://www.cnblogs.com/beretty/p/10778157.html
Copyright © 2011-2022 走看看