没智商了

变式可见:【构造 思维题】7.12道路建设

当你自信满满地把你认为的正确密码输入后,时光机滴滴报警 —— 密码错误。你摊坐在了地上。

黑衣人满意地拍了拍你的肩膀:“小伙子,不错嘛。虽然没解开密码,但是离解开密码也不远咯。其实刚才是个对你的考验。来加入我们保护星期日委员会吧!”

你惊讶得从地上直接 splay 了起来:“就是那个传说中的保护星期日委员会?咦,那为什么今天星期日还要上学呢?”

黑衣人:“你不是高三学生吗?”,你一脸无语。黑衣人又说道:“小伙子跟我干吧,我们一起去摧毁 IIIS。”

于是你们跋山涉水来到了 IIIS 基地的一个秘密仓库门前。duang地一下放倒了门卫之后你们试图开门窃取秘密资料。可是这个门装备了最新的智商锁,只有你的智商恰好等于锁的主人门才会打开。于是门上出现一道迷题:

给你一个 k,请你构造一个结点数不超过 100 的无向图,使得这个无向图中生成树的个数对 $998244353$(7×17×223+1,一个质数)取模后恰为 k。

作为智商超高的你一定一眼秒掉了此题!请写一个程序证明你的智商跟智商锁的主人一样吧!

输入格式

第一行一个正整数 T。

接下来 T 行每行一个非负整数 k,保证 $0≤k<998244353$。

输出格式

你需要对每一个给出来的 $k$,输出一张无自环无重边的无向图。如果有多解输出任意一组解均可。如果无解请输出卖萌表情 “QwQ”(不含引号)。

输出无向图时,先一行两个非负整数 $n,m$,分别表示结点数和边数。你需要满足 $1≤n≤100$。接下来 m 行,每行两个整数 v,u 表示 v 号结点和 u 号结点之间有一条无向边。结点从 1 到 n 编号。


题目分析

随机个1000张图,由于一张点数为$n$的完全图生成树个数为$g_i=n^{n-2}$,那么当$n\ge 10$左右时候$g_i$就可看作在模$p$意义下的一个均匀分布的随机数.

考虑如何由两张图得到一个更大的答案:因为两张图之间本没有边相连,那如果任连一条桥边,就意味着新图的生成树必定要包括这条桥.所以两张图$f,g$可以得到一张新图$h=f\times g$.

接下去就是乱搞用meet in middle找出四元组使得其乘积在模$p$下为$K$.

因为生成的图的生成树数量可视作均匀分布的随机数,所以选四个得到$K$的概率是很大的。

最后还是挂个吉利题解吧……

接下来我们来考虑一种合理的构造方法,直接构造是比较困难的,因为我们现在只能对答案进行乘法(见第七个点)而无法进行加法。于是我们就可以开始尝试乱搞。

标程的做法是:随机1000张点数为12的无向图,用基尔霍夫矩阵求出第$i$张图的生成树个数$f_i$。然后对于每一个$K$,我们试图找到一个四元组$(a,b,c,d)$使得$f_a×f_b×f_c×f_d\equiv K \pmod{998244353}$,这个显然是可以meet in middle的,我们预处理它们两两的乘积与乘积的逆元,借助hash表就可以在约$10^6$级别的运算量下找到一个合法的四元组。

这个做法相当于自行对最终的图添加了一个比较严苛的条件进行求解,为什么这样是靠谱的呢?接下来提供一种对正确性大致的解释(以下是数学渣JRY在没有任何道理的情况进行的口胡):

首先我们随机无向图的方法是每一条边生成的概率都是$0.8$,而12个点的完全图的生成树个数是$12^{10}$,这是远大于模数的,所以我们可以近似地把$fi$看做均匀分布的随机数(这个和我们平时写的哈希表的思想类似)。接下来我们把这$1000$个随机数的集合四次方再模上模数,这样我们就得到了$10^{12}$个数,和刚才同理,我们也可以把这$10^{12}$个数给近似地看成均匀分布的随机数。

接下来我们要求的是$10^{12}$个小于等于$10^9$的随机数完全覆盖0到$10^9$之间所有数的概率是多少。首先一个数被覆盖的概率是$1-(1-\frac{1}{10^9})^{10^{12}} \approx 1-\mathrm{e}^{-10^3}$,我们可以近似地认为所有数都被覆盖的概率是$(1-\mathrm{e}^{-10^3})^{10^9}$,实际上这个数是非常接近$1$的(因为$e^{10^3}$比$10^9$大到哪里去都不知道了)

话说我生成图的方式好像有点奇怪?

 #include<bits/stdc++.h>
#define MO 998244353
const int maxn = ;
const int maxm = ; int qmi(int a, int b)
{
int ret = ;
for (; b; b>>=,a=1ll*a*a%MO)
if (b&) ret = 1ll*ret*a%MO;
return ret;
}
std::set<int> gcnt;
struct Graph
{
int n,m,val;
int fa[maxn],f[maxn][maxn],deg[maxn];
bool mp[maxn][maxn]; Graph(){memset(mp, , sizeof mp);}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int Gauss(int n)
{
int ret = ;
for (int i=; i<=n; i++)
{
if (!f[i][i]) return ;
for (int j=i+; j<=n; j++)
if (f[j][i]){
int det = 1ll*f[j][i]*qmi(f[i][i], MO-)%MO;
for (int k=i; k<=n; k++)
f[j][k] = (f[j][k]-1ll*f[i][k]*det%MO+MO)%MO;
}
}
for (int i=; i<=n; i++)
ret = 1ll*ret*f[i][i]%MO;
return ret;
}
void output(int det)
{
for (int p=; p<=n; p++)
for (int t=p+; t<=n; t++)
if (mp[p][t]) printf("%d %d\n",p+det,t+det);
}
void random(int Range)
{
val = ;
do{
memset(f, , sizeof f);
memset(mp, , sizeof mp);
n = rand()%Range+, m = std::min(n-+rand()%(n*(n-)/-n+), n*(n-)/);
for (int i=; i<=n; i++) fa[i] = i;
for (int i=; i<n; i++)
{
int u = rand()%n+, v = rand()%n+;
while (find(u)==find(v))
u = rand()%n+, v = rand()%n+;
fa[fa[u]] = fa[v];
mp[u][v] = mp[v][u] = true;
f[u][v] = f[v][u] = MO-;
++f[u][u], ++f[v][v];
}
for (int i=n; i<=m; i++)
{
int u = rand()%n+, v = rand()%n+;
while (mp[u][v]||v==u)
u = rand()%n+, v = rand()%n+;
mp[u][v] = mp[v][u] = true;
f[u][v] = f[v][u] = MO-;
++f[u][u], ++f[v][v];
}
for (int i=; i<=n; i++)
for (int j=; j<=n; j++)
if (f[i][j] < ) f[i][j] += MO;
val = Gauss(n-);
}while (gcnt.count(val));
gcnt.insert(val);
}
}f[];
struct node
{
int idx,idy,val;
bool operator < (node a) const
{
return val < a.val;
}
}ddc[];
int T,n,tot;
bool legal; void init()
{
srand(time());
f[].n = f[].val = , gcnt.insert();
f[].n = f[].val = , gcnt.insert();
f[].n = f[].val = , gcnt.insert();
for (int i=; i<=; i++) f[i].random();
for (int i=; i<=; i++) f[i].random();
for (int i=; i<=; i++)
for (int j=i+; j<=; j++)
ddc[++tot].val = 1ll*f[i].val*f[j].val%MO,
ddc[tot].idx = i, ddc[tot].idy = j;
std::sort(ddc+, ddc+tot+);
}
void output(int id1, int id2, int id3, int id4)
{
int det = ;
int n1 = f[id1].n, n2 = f[id2].n, n3 = f[id3].n, n4 = f[id4].n;
if (n1+n2+n3+n4 > ) return;
printf("%d %d\n",n1+n2+n3+n4,f[id1].m+f[id2].m+f[id3].m+f[id4].m+);
f[id1].output(det), det += n1, printf("1 %d\n",det+);
f[id2].output(det), det += n2, printf("1 %d\n",det+);
f[id3].output(det), det += n3, printf("1 %d\n",det+);
f[id4].output(det), det += n4;
legal = true;
}
int main()
{
init();
for (scanf("%d",&T); T; --T)
{
scanf("%d",&n), legal = false;
if (n==){
puts("2 0");continue;
}
for (int i=; i<=&&!legal; i++)
for (int j=i+; j<=&&!legal; j++)
{
int trans = 1ll*n*qmi(1ll*f[i].val*f[j].val%MO, MO-)%MO;
int L = , R = tot, pos = -;
for (int mid=(L+R)>>; L<=R; mid=(L+R)>>)
if (ddc[mid].val <= trans) pos = mid, L = mid+;
else R = mid-;
if (ddc[pos].val==trans)
output(ddc[pos].idx, ddc[pos].idy, i, j);
}
if (!legal) puts("QwQ");
}
return ;
}

END

最新文章

  1. for循环嵌套执行效率
  2. 转--脉络清晰的BP神经网络讲解,赞
  3. [stm32] SIM808模块之发短信\GPS\TCP\HTTP研究
  4. [linux] FastDFS访问文件,400 Bad Request
  5. Linux 硬盘分区
  6. Spring整合CXF,发布RSETful 风格WebService(转)
  7. RichTextBox控件-主要用于输入输出编辑文本信息
  8. 使用原始XML资源——定义原始XML资源
  9. 【Git】自动化Maven项目构建脚本(一)
  10. A1135. Is It A Red-Black Tree
  11. springboot打成Jar包后部署至Linux服务器上
  12. 【转】C语言中,为什么字符串可以赋值给字符指针变量
  13. mysql补充(4)数据完整性
  14. Mac Supervisor 管理进程
  15. mac 安装secureCRT
  16. DevExpress RichEditControl 上下翻页功能 z
  17. Js 向json对象中添加新元素
  18. ptxas fatal : Unresolved extern function Error 255
  19. 如何通过Xcode 5中集成的XCTest框架进行简单的单元测试
  20. JavaScript 刚開始学习的人应知的 24 条最佳实践

热门文章

  1. 数据库工具DbVisualize安装、破解教程,亲测可用
  2. DAY 吐
  3. Hive概述
  4. mysql 插入数据后返回自增 ID 的七种方法
  5. Stream系列(八)Reduce方法使用
  6. PYTHON 100days学习笔记004:循环结构
  7. JAVA汽车4S店管理系统
  8. 向量运算(lua,三维) 点乘、叉乘、模、夹角
  9. Open API
  10. 国内有哪些好的JAVA社区