UOJ

思路

我们知道关于有向图欧拉回路计数有一个结论:在每个点入度等于出度的时候,答案就是

\[t_w(G)\prod (deg_i-1)!
\]

其中\(t_w(G)\)是以某个点为根的树形图个数。(必须确定是外向树还是内向树)

(由这个公式,我们可以知道这种图下面以每个点为根的外向树和内向树的个数都是一样的,但我不会证/kk)

还有一个结论,不过这题用不上:对于一个有向图,以点\(x\)为根的树的个数是用度数矩阵减去邻接矩阵,再删去第\(x\)行第\(x\)列,的行列式。其中那个度数矩阵如果求内向树那么就是出度,外向树就是入度。

所以在图是一棵树的时候,显然每组边都会有一半向上一半向下,就可以得到答案。

基环树的时候,其实问题就转化为给环上的边定向。

我们可以枚举某一条边的定向方案,然后就可以推出其他所有边。

然后再求一下树形图个数,就做完了。

代码

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 10101
#define mod 998244353ll
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std; ll fac[sz<<10],_fac[sz<<10];
void init()
{
_fac[0]=fac[0]=1;
rep(i,1,sz*1e3) fac[i]=fac[i-1]*i%mod;
_fac[sz*(int)1e3]=inv(fac[sz*(int)1e3]);
drep(i,sz*1e3-1,1) _fac[i]=_fac[i+1]*(i+1)%mod;
}
ll C(int n,int m){return n>=m&&m>=0?fac[n]*_fac[m]%mod*_fac[n-m]%mod:0;} int n,m;
struct hh{int t,nxt,cnt;}edge[sz<<1];
int head[sz],ecnt=1;
int deg[sz];
void make_edge(int f,int t,int cc)
{
edge[++ecnt]=(hh){t,head[f],cc};
head[f]=ecnt;
edge[++ecnt]=(hh){f,head[t],cc};
head[t]=ecnt;
deg[f]+=cc,deg[t]+=cc;
} namespace Tree
{
int solve()
{
ll ans=1;
rep(i,1,n) ans=ans*fac[deg[i]/2-1]%mod;
rep(i,1,n-1) ans=ans*C(edge[i<<1].cnt,edge[i<<1].cnt/2)%mod*edge[i<<1].cnt/2%mod;
cout<<ans;
return 0;
}
} namespace WTF
{
ll prod=1;
int incir[sz];
vector<pii>cir; // fir: the point in the circle; sec: the edge that connects itself and the previous one
int vis[sz],in[sz];
#define v edge[i].t
int dfs(int x,int fa)
{
int ret=0,id=0;
in[x]=vis[x]=1;
go(x) if (v!=fa)
{
if (!vis[v])
{
int cur=dfs(v,x);
if (!cur) { prod=prod*C(edge[i].cnt,edge[i].cnt/2)%mod*edge[i].cnt/2%mod; continue; }
ret=cur;id=i;
}
else if (in[v]) ret=v,id=i;
}
if (ret) cir.push_back(MP(x,id)),incir[x]=1;
if (ret==x) ret=0;
prod=prod*fac[deg[x]/2-1]%mod;
in[x]=0;
return ret;
}
#undef v
int L[sz],R[sz]; // 出度
int L_[sz],R_[sz]; // 入度
ll pre[sz],suf[sz];
int solve()
{
dfs(1,0);
int m=(int)cir.size()-1;
ll ans=0;
rep(k,0,edge[cir[0].sec].cnt)
{
R_[m]=L[0]=k;R[m]=L_[0]=edge[cir[0].sec].cnt-k;
rep(i,0,m-1)
{
int delta=L[i]-L_[i],cnt=edge[cir[i+1].sec].cnt;
L_[i+1]=R[i]=(cnt-delta)/2;L[i+1]=R_[i]=(cnt+delta)/2;
}
bool flg=1;
rep(i,0,m) if (L[i]<0||R[i]<0) flg=0;
if (!flg) continue;
ll cur=prod;
rep(i,0,m) cur=cur*C(edge[cir[i].sec].cnt,L[i])%mod;
pre[0]=1;rep(i,1,m) pre[i]=pre[i-1]*L[i]%mod;
suf[m+1]=1;drep(i,m,1) suf[i]=suf[i+1]*R[i]%mod;
rep(i,0,m) (ans+=cur*pre[i]%mod*suf[i+1]%mod)%=mod;
}
cout<<ans;
return 0;
}
} int main()
{
file();
init();
read(n,m);
int x,y,z;
rep(i,1,m) read(x,y,z),make_edge(x,y,z);
rep(i,1,n) if (deg[i]&1) return puts("0"),0;
if (m==n-1) return Tree::solve();
return WTF::solve();
}

UOJ226. 【UR #15】奥林匹克环城马拉松 [组合数学,图论]的更多相关文章

  1. 【uoj#225】[UR #15]奥林匹克五子棋 构造

    题目描述 两个人在 $n\times m$ 的棋盘上下 $k$ 子棋,问:是否存在一种平局的情况?如果存在则输出一种可能的最终情况. 输入 第一行三个正整数 $n,m,k$ ,意义如前所述. 输出 如 ...

  2. UOJ Round #15 [构造 | 计数 | 异或哈希 kmp]

    UOJ Round #15 大部分题目没有AC,我只是水一下部分分的题解... 225[UR #15]奥林匹克五子棋 题意:在n*m的棋盘上构造k子棋的平局 题解: 玩一下发现k=1, k=2无解,然 ...

  3. WinAFL

    winafl 标签(空格分隔): fuzz 构成 afl-fuzz.c 主模块 读取文件 维护testcase queue 进行mutate fuzz_one 评估代码覆盖率 执行遗传算法 更新界面 ...

  4. 转:智能模糊测试工具 Winafl 的使用与分析

    本文为 椒图科技 授权嘶吼发布,如若转载,请注明来源于嘶吼: http://www.4hou.com/technology/2800.html 注意: 函数的偏移地址计算方式是以IDA中出现的Imag ...

  5. 关于SPFA算法的优化方式

    关于SPFA算法的优化方式 这篇随笔讲解信息学奥林匹克竞赛中图论部分的求最短路算法SPFA的两种优化方式.学习这两种优化算法需要有SPFA朴素算法的学习经验.在本随笔中SPFA朴素算法的相关知识将不予 ...

  6. HDU-6125-Friend-Graph-2017CCPC网络赛(图论,拉姆齐定理-组合数学)

    Friend-Graph Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) To ...

  7. Python小白的数学建模课-15.图论基本概念

    图论中所说的图,不是图形图像或地图,而是指由顶点和边所构成的图形结构. 图论不仅与拓扑学.计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术. 本系列结合数学建模的应用需求,来介绍 Netw ...

  8. 【uoj#22】[UR #1]外星人 组合数学+dp

    题目描述 给你一个长度为 $n$ 的序列 $\{a_i\}$ 和一个数 $x$ ,对于任意一个 $1\sim n$ 的排列 $\{p_i\}$ ,从 $1$ 到 $n$ 依次执行 $x=x\ \tex ...

  9. 刷题向》图论》BZOJ1179 关于tarjan和SPFA的15秒(normal)

    这道题可以考察图论的掌握程度(算半道水题) 题目如下 输入 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i ...

随机推荐

  1. OO——JML作业总结

    目录 第三单元博客作业 JML语言理论基础 1.注释结构 2.JML表达式 3.方法规格 4.类型规格 应用工具链 JMLUnitNG使用实例 作业架构设计 第一次作业 第二次作业 第三次作业 BUG ...

  2. Unity3d与iOS交互开发

    一.Unity3d  To  iOS: 最近要做一个商品和人体模型T台秀相关的功能,要用到Unity3D,搜集了一些资料先保存下来. 1.创建一个C#文件 SdkToIOS.cs 这是调用iOS函数的 ...

  3. vue实现滑块滑动校验

    为了防止机器操作自动提交,我们需要添加滑动校验. 实现代码如下:   1.子组件slider.vue <template> <div class="drag" r ...

  4. tp5模板中js方法中url函数传参的解决办法

    代码如下: layer.msg(data.msg, {icon: 1,time:1500,shade: 0.1}, function(index){ layer.close(index); var s ...

  5. day26-python之封装

    1.动态导入模块 # module_t=__import__('m1.t') # print(module_t) # module_t = __import__('m1.t') # print(mod ...

  6. Android查看应用方法数

    当一个项目快速迭代时,难免引进各种依赖,从而导致单个apk超过65k的限制.如何查询apk的方法数也是每个Android Developer必备技能. 我使用的是 dex-method-counts  ...

  7. II、Vue的项目目录结构 一些语法

    Vue目录结构 这是某闭源项目的web端目录结构: 目录解析: -目录/文件 - build 项目构建(webpack)相关代码 config 配置目录.端口号:也有默认的 node_modules ...

  8. git如何删除已经提交的文件夹

    在上传项目到github时,忘记忽略了某个文件夹.idea,就直接push上去了, 最后意识到了此问题,决定删除掉远程仓库中的.idea文件夹 删除前: 删除后: 在github上只能删除仓库,却无法 ...

  9. mac 下enable mysql的load data in file

    1)使用root用户登录mysql 2)将 local_infile 变量设置为true SET GLOBAL local_infile = true; 3)重启数据库 在系统偏好设置中找到MySql ...

  10. Flink使用(二)——Flink集群资源规划

    前言 本文主要译自Flink Forward 2017的柏林站中Robert Metzger的有关集群规划的How to size your flink cluster一文.该文中主要是考虑网络资源, ...