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. java之struts2的ThreadLocal和ActionContext

    在之前的学习中,我们知道struts2可以将表单中的数据自动设置到处理类的属性上,还有类型转换等其他功能.那么struts2是怎样做这件事情的呢? struts2完成这些功能是通过拦截器来完成的,并且 ...

  2. JavaScript的书写格式及书写的注意点

    JavaScript书写格式: 1.行内样式: 写在标签内部 2.内嵌样式(内联样式) : 写在一对head标签中 3.外链样式: 写在一个单独的.js文件中, 再导入进来 JavaScript书写格 ...

  3. echart 人头

    <template> <div :class="className"> <div :id="id" class="spi ...

  4. java设计模式--观察者模式和事件监听器模式

    观察者模式 观察者模式又称为订阅—发布模式,在此模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知.这通常透过呼叫各观察者所提供的方法来实现.此种模式通常被用来事件 ...

  5. p1.BTC-密码学的原理

    所谓加密货币是不加密的,区块链上所有的交易内容(包括:账户的地址,转账的地址)都是公开的. Bitcoin中主要用到密码学的中的两个功能:Hash和签名. 一 Hash Cryptographic h ...

  6. Unable to guess the mime type as no guessers are available 2 9

    做了一个上传图片的功能,在本地上传通过,服务器报 bug Unable to guess the mime type as no guessers are available(Did you enab ...

  7. python中csv模块和join函数的使用

    在看项目的时候恰好又碰到了这两个功能,然后稍微记录一下,关于join函数,是一个经常使用的联合函数,作用就是用自己规定的字符去串联字符串和列表之类的,对于字符串来说,join函数针对的是字符串中的每一 ...

  8. Java获取各种路径

    (1).request.getRealPath("/");//不推荐使用获取工程的根路径(2).request.getRealPath(request.getRequestURI( ...

  9. 2013.6.22 - OpenNE第二天

    果然看中文材料就比较顺利,才半个小时就看完了一篇非常简单的综述<命名实体识别研究进展综述>(孙镇.王惠临).这个是2010年的文章,其实就是一个 科普文章,简述了国内外NER这块的历史如何 ...

  10. MongonDB 知识

    配置 vi  mongodb.conf dbpath=/usr/local/mongodb/data/ logpath=/usr/local/mongodb/data/mongodb.log port ...