(以下假设$T=(V,\{e_{1},e_{2},...,e_{n-1} \})$是一棵树)
根据莫比乌斯反演,有$\gcd(w_{1},w_{2},...,w_{e_{n-1}})=\sum_{d|w_{e_{i}}}\varphi(d)$
容易想到枚举$d$,之后相当于求$\sum_{d}\varphi(d)\sum_{d|w_{e_{i}}}\sum_{i=1}^{n-1} w_{e_{i}}$
那么即找出所有权值为$d$的倍数的边,然后求所有生成树的边权和的和,但矩阵树定理只能求边权积之和(将邻接矩阵权值改为边权,将度数矩阵的度数改为出边的边权和,即【bzoj3534】)
考虑令边i的边权为$1+w_{i}x$,那么容易发现所有边权乘积的和的1次项系数即为答案
同时多项式只需要维护0次项和1次项(即模$x^{2}$意义下运算),因此复杂度为$o(dn^{3})$,仍然无法通过
考虑一个优化:如果$d$的倍数的边小于$n-1$条,显然无解;那么最坏的构造方式为:选出n组边,每组n条边边权相同,那么最多有有$2\sqrt{d}n$种合法的d,复杂度降为$o(\sqrt{d}n^{4})$,且其中会产生许多重复边权,并不会跑满
还有一件事情,这样的高斯消元会有很多细节:
1.多项式除法,由于在模$x^{2}$意义下,所以直接手动解方程推出$(ax+b)^{-1}\equiv \frac{1}{b}-\frac{a}{b^{2}}x(mod\ x^{2})$
2.若存在常数项非0,将该点与当前行交换;若不存在,那么直接用一次项系数消除(因为常数项都为0),即$inv(ax)=a^{-1}$

  1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 35
4 #define D 152501
5 #define mod 998244353
6 #define mp make_pair
7 #define pii pair<int,int>
8 #define fi first
9 #define se second
10 struct ji{
11 int nex,to,len;
12 }edge[N*N];
13 int E,n,m,x,y,z,ans,head[N],p[D+10],phi[D+10];
14 pii d[N][N];
15 int ksm(int n,int m){
16 if (!m)return 1;
17 int s=ksm(n,m>>1);
18 s=1LL*s*s%mod;
19 if (m&1)s=1LL*s*n%mod;
20 return s;
21 }
22 pii add(pii x,pii y){
23 return mp((x.fi+y.fi)%mod,(x.se+y.se)%mod);
24 }
25 pii mul(pii x,pii y){
26 return mp(1LL*x.fi*y.fi%mod,(1LL*x.fi*y.se+1LL*x.se*y.fi)%mod);
27 }
28 pii inv(pii x){
29 if (!x.fi)return mp(ksm(x.se,mod-2),0);
30 int s=ksm(x.fi,mod-2);
31 return mp(s,mod-1LL*x.se*s%mod*s%mod);
32 }
33 void add(int x,int y,int z){
34 edge[E].nex=head[x];
35 edge[E].to=y;
36 edge[E].len=z;
37 head[x]=E++;
38 }
39 int find1(int k){
40 for(int i=k;i<n;i++)
41 if (d[i][k].fi)return i;
42 return 0;
43 }
44 int find2(int k){
45 for(int i=k;i<n;i++)
46 if (d[i][k].se)return i;
47 return 0;
48 }
49 int main(){
50 phi[1]=1;
51 for(int i=2;i<=D;i++){
52 if (!phi[i]){
53 p[++p[0]]=i;
54 phi[i]=i-1;
55 }
56 for(int j=1;(j<=p[0])&&(i*p[j]<=D);j++){
57 if (i%p[j])phi[i*p[j]]=phi[i]*phi[p[j]];
58 else{
59 phi[i*p[j]]=phi[i]*p[j];
60 break;
61 }
62 }
63 }
64 scanf("%d%d",&n,&m);
65 memset(head,-1,sizeof(head));
66 for(int i=1;i<=m;i++){
67 scanf("%d%d%d",&x,&y,&z);
68 add(x,y,z);
69 add(y,x,z);
70 }
71 for(int i=1;i<=D;i++){
72 x=0;
73 for(int j=0;j<E;j+=2)
74 if (edge[j].len%i==0)x++;
75 if (x<n-1)continue;
76 memset(d,0,sizeof(d));
77 for(int j=1;j<n;j++)
78 for(int k=head[j];k!=-1;k=edge[k].nex)
79 if (edge[k].len%i==0){
80 d[j][j]=add(d[j][j],mp(1,edge[k].len));
81 if (edge[k].to<n)d[j][edge[k].to]=mp(mod-1,mod-edge[k].len);
82 }
83 pii s=mp(1,0);
84 for(int j=1;j<n;j++){
85 x=find1(j);
86 if (!x)y=find2(j);
87 if (!x){
88 s.se=0;
89 break;
90 }
91 if (x!=j){
92 s=mp(mod-s.fi,mod-s.se);
93 for(int k=j;k<n;k++)swap(d[j][k],d[x][k]);
94 }
95 s=mul(s,d[j][j]);
96 pii t=inv(d[j][j]);
97 for(int k=j;k<n;k++)d[j][k]=mul(d[j][k],t);
98 for(int k=j+1;k<n;k++){
99 t=mp(mod-d[k][j].fi,mod-d[k][j].se);
100 for(int l=j;l<n;l++)d[k][l]=add(d[k][l],mul(t,d[j][l]));
101 }
102 }
103 ans=(ans+1LL*s.se*phi[i])%mod;
104 }
105 printf("%d",ans);
106 }

[loj3304]作业题的更多相关文章

  1. nyoj201 作业题

    作业题 时间限制: 3000 ms  |  内存限制: 65535 KB 难度: 3   描述 小白同学这学期有一门课程叫做<数值计算方法>,这是一门有效使用数字计算机求数学问题近似解的方 ...

  2. NYOJ201作业题

    作业题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 小白同学这学期有一门课程叫做<数值计算方法>,这是一门有效使用数字计算机求数学问题近似解的方法与过程, ...

  3. [ python ] 字符串的操作及作业题

    字符串的操作方法 capitalize() : 首字母大写 s1 = 'my heart will go on' print(s1.capitalize()) # 首字母大写 # 执行结果: # My ...

  4. nyoj 作业题 dp

    作业题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 小白同学这学期有一门课程叫做<数值计算方法>,这是一门有效使用数字计算机求数学问题近似解的方法与过程, ...

  5. NYOJ 201 作业题

    作业题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 小白同学这学期有一门课程叫做<数值计算方法>,这是一门有效使用数字计算机求数学问题近似解的方法与过 ...

  6. 作业题:闰年 if((year%4==0&&year%100!=0)||year&400==0)

    作业题:闰年 if((year%4==0&&year%100!=0)||year&400==0)

  7. python27期day14:有参装饰器、多个装饰器装饰一个函数、递归、作业题

    1.有参装饰器:给装饰器添加一个参数.来控制装饰器的行为. @auth(参数) auth里层的函数名 = auth(参数) 被装饰的函数名 = auth里层的函数名(被装饰的函数名) 被装饰的函数名( ...

  8. python27期day13:闭包、装饰器初始、标准版装饰器、作业题

    1.闭包: 保护数据安全.保护数据干净性. 2.闭包的定义:在嵌套函数内.使用非全局变量(且不使用本层变量) 将嵌套函数返回 闭包的目的:要接受被装饰的函数和被装饰函数需要的参数3.闭包举例子: de ...

  9. python27期day12:推导式、内置函数、高阶函数、匿名函数、作业题

    1.推导式:做一些有规律的数据结构 列表推导式: 普通循环模式: [加工后的变量 for 循环] 示例一:print([i for i in range(1,51)]) 结果:[1, 2, 3, 4, ...

随机推荐

  1. Git学习笔记03-原理

    在Git中,算上远程Git仓库有四个工作区域 Git本地有三个区域(工作区域.暂存区,资源区,远程Git仓库) 工作区域:就是你本机写好的代码,你可以看到的 暂存区:你写好的代码上传后被git管理的内 ...

  2. Python实现九九乘法表

  3. 重磅!微软发布 vscode.dev,把 VS Code 带入浏览器!

    早在 2019 年,当.dev顶级域名开放时,我们赶紧注册了vscode.dev.像许多购买.dev域名的人一样,我们不知道我们将用它做啥.反正,也占个坑吧! 将 VS Code 带入浏览器 直到今天 ...

  4. Golang通脉之类型定义

    自定义类型 在Go语言中有一些基本的数据类型,如string.整型.浮点型.布尔等数据类型, Go语言中可以使用type关键字来定义自定义类型. type是Go语法里的重要而且常用的关键字,type绝 ...

  5. [对对子队]Scrum Meeting 博客汇总

    对对子队 博客目录 一.Scrum Meeting 1. Alpha Scrum Meeting 1(会议记录4.10) Scrum Meeting 2(会议记录4.11) Scrum Meeting ...

  6. UltraSoft - Beta - Scrum Meeting 3

    20200519会议纪要 Date: May 19th, 2020. Scrum 情况汇报 进度情况 组员 负责 今日进度 q2l PM.后端 暂无 Liuzh 前端 暂无 Kkkk 前端 完成了前端 ...

  7. Prometheus之告警规则的编写

    Prometheus之告警规则的编写 一.前置知识 二.需求 三.实现步骤 1.编写告警规则 2.修改prometheus.yml执行告警规则的位置 3.配置文件截图 4.页面上看告警数据信息 5.查 ...

  8. 大厂面试题系列:重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分

    面试题:重载(Overload)和重写(Override)的区别.重载的方法能否根据返回类型进行区分 面试官考察点猜想 这道题纯粹只是考查基础理论知识,对实际开发工作中没有太多的指导意义,毕竟编辑器都 ...

  9. Spark面试题整理(三)

    1.为什么要进行序列化序列化? 可以减少数据的体积,减少存储空间,高效存储和传输数据,不好的是使用的时候要反序列化,非常消耗CPU. 2.Yarn中的container是由谁负责销毁的,在Hadoop ...

  10. HTML基础强化

    1.如何理解HTML? HTML类似于一份word"文档" 描述文档的"结构" 有区块和大纲 2.对WEB标准的理解? Web标准是由一系列标准组合而成.一个网 ...