题面传送门

一道很神的矩阵树定理+乱搞的题 %%%%%%%%%%%%%%% vfk yyds

u1s1 这种题目我是根本想不出来/kk,大概也就 jgh 这样的随机化带师才能想到出来吧

首先看到生成树计数可以很显然地想到矩阵树定理,但是由于此题是根据生成树个数构造合法的解的方案,所以一看就没有什么正经的做法(有提答题内味儿了)。

一个很显然的性质是:对于一张图我们可以考虑将其进行边双连通分量缩点,那么最终的生成树个数显然等于所有边双连通分量中生成树的乘积。这就启发我们采用这样一个思想,将原来 \(100\) 个点的图拆成若干个部分,对每个部分进行随机化,然后再像串糖葫芦一样将这些部分串起来。

然后就是我所想不到的地方了,考虑随机生成 \(1000\) 张由 \(15\) 个顶点(原题解是 \(12\) 个点,不过我认为都差不多罢)组成的图,每条边都有 \(70\%\) 的概率出现,并用矩阵树定理计算其中生成树的数量,我们记 \(f_i\) 表示第 \(i\) 张图的生成树个数 \(\bmod 998244353\),那么我们考虑求出一个四元组 \((a,b,c,d)\) 满足 \(f_af_bf_cf_d\equiv k\pmod{998244353}\),那么我们把 \(a,b,c,d\) 四张图串成一条链,形成一个 \(60\) 个点的图即可。那么怎么找出符合要求的 \((a,b,c,d)\) 呢?考虑用 meet-in-the-middle 的思想,枚举二元组 \(a,b\) 并将 \(f_af_b\) 的值放入一个 hashtable,然后枚举 hashtable 中的元素 \(v\) 并查看 \(k·v^{-1}\) 是否在 hashtable 中,这样即可在 \(\mathcal O(10^6)\) 的时间内求出符合要求的 \((a,b,c,d)\)。

最后我们要说明的问题是为什么这样做是正确的,或者说,为什么这个做法获得正确答案的概率很大。首先我们知道 \(15\) 个点的完全图中有 \(15^{13}\) 个生成树,该值是远远大于 \(998244353\) 的,也就是说这样的图的生成树个数在模上 \(998244353\) 中可以近似地看作均匀分布的,也就是说我们等价于随机生成了 \(1000\) 个 \(<998244353\) 的数,而这 \(1000\) 个数两两配对共可以得到 \(\dbinom{1000}{4}\approx 10^{11}\) 个不同的数,也就是说本题能够获得正确答案的概率等价于 \(10^{11}\) 个 \(<998244353\) 的数中包含全部 \(0\sim 998244352\) 的数的概率,简单想想就知道这个概率是很大的,如果真的要定量计算的话,那么每个数被覆盖的概率就是 \(1-(1-\dfrac{1}{998244353})^{10^{11}}\approx 1-e^{-100}\),该值大约是 \(1-10^{-44}\),这样一来所有数都被覆盖的概率大约就是 \((1-10^{-44})^{998244353}\),我用计算器摁了一下,\((1-10^{-28})^{10^9}\) 大约是 \(0.99997\),而前者显然比后者更大,因此正确性是可以保证的。

最后注意特判 \(k=0\),因为生成树个数为 \(998244353\) 的倍数的概率显然远远小于不是 \(998244353\) 的倍数。

const int MOD=998244353;
int qpow(int x,int e){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
return ret;
}
struct graph{
bool has[17][17];
int a[17][17],cnt;
void add(int x,int y){
x--;y--;
a[x][y]=(a[x][y]-1+MOD)%MOD;
a[y][x]=(a[y][x]-1+MOD)%MOD;
a[x][x]=(a[x][x]+1)%MOD;
a[y][y]=(a[y][y]+1)%MOD;
}
int getdet(){
int sgn=1;
for(int i=1;i<15;i++){
int t=i;
for(int j=i+1;j<15;j++) if(a[j][i]) t=j;
if(t!=i) sgn=-sgn;
for(int j=i;j<15;j++) swap(a[i][j],a[t][j]);
int iv=qpow(a[i][i],MOD-2);
for(int j=i+1;j<15;j++){
int mul=1ll*(MOD-a[j][i])*iv%MOD;
for(int k=i;k<15;k++) a[j][k]=(a[j][k]+1ll*mul*a[i][k])%MOD;
}
} int res=(sgn+MOD)%MOD;
for(int i=1;i<15;i++) res=1ll*res*a[i][i]%MOD;
return res;
}
void gen(){
for(int i=1;i<=15;i++) for(int j=1;j<i;j++){
int pro=rand()%10;
if(pro>2) has[i][j]=has[j][i]=1,add(i,j);
} cnt=getdet();
}
} g[1005];
map<int,pii> mul;
int main(){
srand(20060729);
for(int i=1;i<=1000;i++) g[i].gen();
for(int i=1;i<=1000;i++) for(int j=1;j<=i;j++)
mul[1ll*g[i].cnt*g[j].cnt%MOD]=mp(i,j);
int qu;scanf("%d",&qu);
while(qu--){
int t;scanf("%d",&t);
if(!t){printf("%d %d\n%d %d\n",3,1,1,2);continue;}
for(map<int,pii>::iterator it=mul.begin();it!=mul.end();it++){
int val=it->fi,rst=1ll*t*qpow(val,MOD-2)%MOD;
if(mul.count(rst)){
vector<pii> ans;
int a=it->se.fi,b=it->se.se,c=mul[rst].fi,d=mul[rst].se;
// printf("%d %d %d %d\n",a,b,c,d);
// printf("%d %d %d %d\n",g[a].cnt,g[b].cnt,g[c].cnt,g[d].cnt);
for(int i=1;i<=15;i++) for(int j=1;j<i;j++) if(g[a].has[i][j]) ans.pb(mp(i,j));
for(int i=1;i<=15;i++) for(int j=1;j<i;j++) if(g[b].has[i][j]) ans.pb(mp(15+i,15+j));
for(int i=1;i<=15;i++) for(int j=1;j<i;j++) if(g[c].has[i][j]) ans.pb(mp(30+i,30+j));
for(int i=1;i<=15;i++) for(int j=1;j<i;j++) if(g[d].has[i][j]) ans.pb(mp(45+i,45+j));
ans.pb(mp(1,16));ans.pb(mp(16,31));ans.pb(mp(31,46));
printf("%d %d\n",60,ans.size());
for(pii e:ans) printf("%d %d\n",e.fi,e.se);
break;
}
}
}
return 0;
}

UOJ 75 - 【UR #6】智商锁(矩阵树定理+随机+meet-in-the-middle)的更多相关文章

  1. 【UOJ#75】【UR #6】智商锁(矩阵树定理,随机)

    [UOJ#75][UR #6]智商锁(矩阵树定理,随机) 题面 UOJ 题解 这种题我哪里做得来啊[惊恐],,, 题解做法:随机\(1000\)个点数为\(12\)的无向图,矩阵树定理算出它的生成树个 ...

  2. 矩阵树定理&BEST定理学习笔记

    终于学到这个了,本来准备省选前学来着的? 前置知识:矩阵行列式 矩阵树定理 矩阵树定理说的大概就是这样一件事:对于一张无向图 \(G\),我们记 \(D\) 为其度数矩阵,满足 \(D_{i,i}=\ ...

  3. [spoj104][Highways] (生成树计数+矩阵树定理+高斯消元)

    In some countries building highways takes a lot of time... Maybe that's because there are many possi ...

  4. BZOJ 4766: 文艺计算姬 [矩阵树定理 快速乘]

    传送门 题意: 给定一个一边点数为n,另一边点数为m,共有n*m条边的带标号完全二分图$K_{n,m}$ 求生成树个数 1 <= n,m,p <= 10^18 显然不能暴力上矩阵树定理 看 ...

  5. bzoj 4596 [Shoi2016]黑暗前的幻想乡 矩阵树定理+容斥

    4596: [Shoi2016]黑暗前的幻想乡 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 559  Solved: 325[Submit][Sta ...

  6. 【LOJ#6072】苹果树(矩阵树定理,折半搜索,容斥)

    [LOJ#6072]苹果树(矩阵树定理,折半搜索,容斥) 题面 LOJ 题解 emmmm,这题似乎猫讲过一次... 显然先\(meet-in-the-middle\)搜索一下对于每个有用的苹果数量,满 ...

  7. 2019.01.02 bzoj2467: [中山市选2010]生成树(矩阵树定理)

    传送门 矩阵树定理模板题. 题意简述:自己看题面吧太简单懒得写了 直接构建出这4n4n4n个点然后按照题面连边之后跑矩阵树即可. 代码: #include<bits/stdc++.h> # ...

  8. [CF917D]Stranger Trees[矩阵树定理+解线性方程组]

    题意 给你 \(n\) 个点的无向完全图,指定一棵树 \(S\),问有多少棵生成树和这棵树的公共边数量为 \(k\in[0,n-1]\) \(n\leq 100\) 分析 考虑矩阵树定理,把对应的树边 ...

  9. 【bzoj4596】[Shoi2016]黑暗前的幻想乡 容斥原理+矩阵树定理

    题目描述 给出 $n$ 个点和 $n-1$ 种颜色,每种颜色有若干条边.求这张图多少棵每种颜色的边都出现过的生成树,答案对 $10^9+7$ 取模. 输入 第一行包含一个正整数 N(N<=17) ...

随机推荐

  1. linux Samba 搭建

    Samba is a free and open-source software package that provides seamless file and print services to S ...

  2. part1 软件测试基础知识面试题(含答案)

    1.你的测试职业发展是什么? 测试经验越多,测试能力越高.所以我的职业发展是需要时间积累的,一步步向着高级测试工程师奔去.而且我也有初步的职业规划,前3年积累测试经验,按如何做好测试工程师的要点去要求 ...

  3. kafka应用讲解及应用场景(三)

    一. 验证 1.进入bin目录 cd bin 2.ls查看脚本 会发现下面有很多脚本文件,由于我是要创建一个topic所有直接打开kafka-topics.sh脚本查看命令 打开脚本后发现里面有很多命 ...

  4. 跟着老猫一起来学GO,环境搭建

    老猫的GO学习系列博客已经正式发车了,相信大家以前学习一门编程语言的时候也有经验,咱们一般都是从环境开始,在此呢,大家也跟着老猫从最开始的搭建环境开始. GO语言的安装 首先呢,我们开始需要下载GO语 ...

  5. HttpClient.PatchAsJsonAsync - dotnet/runtime 项目贡献小记

    TL;DR 迫于 PatchAsJsonAsync 方法缺失,我给 dotnet/runtime 项目贡献了相关的 API,可惜要到 .NET7 才能用上. https://github.com/do ...

  6. Java版人脸检测详解下篇:编码

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  7. netty入门实现简单的echo程序

    最近看以往在程序中编写的代码,发现有一个功能是使用socket通讯来实现的,而那个时候使用的是基于bio的阻塞io来实现的,最近在看netty,发现可以使用netty来使用nio的方式来实现,此博客记 ...

  8. 关于评论区empty。。。

    空荡荡的毫无人烟,博主希望路过的小哥哥/小姐姐(几率较小)留下些什么--

  9. 牛客网 剑指Offer 索引

    二维数组中的查找 替换空格 从尾到头打印链表 重建二叉树 用两个栈实现队列 旋转数组的最小数字 斐波那契数列 跳台阶 变态跳台阶 矩形覆盖 二进制中1的个数 数值的整数次方 调整数组顺序使奇数位于偶数 ...

  10. SpirngBoot整合Mybatis Plus多数据源

    导读 有一个这样子的需求,线上正在跑的业务,由于业务发展需要,需重新开发一套新系统,等新系统开发完成后,需要无缝对接切换,当初具体设计见草图. 添加依赖 <!--lombok--> < ...