zoukankan      html  css  js  c++  java
  • [loj3304]作业题

    (以下假设$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条边边权相同,那么最多有有$2sqrt{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 }
    View Code
  • 相关阅读:
    Nmap帮助文档解释
    用servlet设置过滤器处理中文乱码
    Linux服务器远程连接window服务器并执行cmd命令
    java中的异常处理
    java的反射机制
    react入门
    多线程编程
    软件工程基本概念
    反射、类加载与垃圾回收
    数据库
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13411961.html
Copyright © 2011-2022 走看看