loj6271 「长乐集训 2017 Day10」生成树求和 加强版(矩阵树定理,循环卷积)
loj6271 「长乐集训 2017 Day10」生成树求和 加强版(矩阵树定理,循环卷积)
题解时间
首先想到先分开三进制下每一位,然后每一位分别求结果为0,1,2的树的个数。
然后考虑矩阵树求出来的是树的边权之积的和,而我们要求树的边权的不进位三进制和的和。
由于矩阵树求出来的是树的边权之积的和,考虑暴力上生成函数求解循环卷积,结果就是 $ c $ 的项的系数和。
但很明显生成函数暴力算是没得整的。
所以我们想到了利用单位根实现的k进制FWT。
很幸运的 $ \omega_{ 3 }^{ 2 } = - \omega_{ 3 } -1 $ 。
这样一来数值可以直接用一个 $x + y \omega_{ 3 } $ 来表示。
求出每一位的点值之后直接IFWT回去。
但是我不会(悲)
代码
为什么会有文件读写啊,正巧在loj刚咕完恢复过来的时候交,T了好多次以为loj评测姬也咕了呢。。。
不就是你自己不好好读题。
#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
struct pat{int x,y;pat(int x=0,int y=0):x(x),y(y){}bool operator<(const pat &p)const{return x==p.x?y<p.y:x<p.x;}};
template<typename TP>inline void read(TP &tar)
{
TP ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){ret=ret*10+(ch-'0');ch=getchar();}
tar=ret*f;
}
template<typename TP,typename... Args>inline void read(TP& t,Args&... args){read(t),read(args...);}
namespace RKK
{
const int N=110,M=5011,C=19683;
const int mo=1000000007,inv3=333333336;
void doadd(int &a,int b){if((a+=b)>=mo) a-=mo;}int add(int a,int b){return (a+=b)>=mo?a-mo:a;}
void dodec(int &a,int b){doadd(a,mo-b);}int dec(int a,int b){return add(a,mo-b);}
void domul(int &a,int b){a=1ll*a*b%mo;}int mul(int a,int b){return 1ll*a*b%mo;}
int fpow(int a,int p){int ret=1;while(p){if(p&1) domul(ret,a);domul(a,a),p>>=1;}return ret;}
struct cp
{
int x,y;//x+yw
cp(const int &x=0,const int &y=0):x(x),y(y){}
operator bool(){return x||y;}
cp inv()const{int i=fpow(dec(add(mul(x,x),mul(y,y)),mul(x,y)),mo-2);return cp(mul(dec(x,y),i),mul(dec(0,y),i));}
cp operator+(const cp &p)const{return cp(add(x,p.x),add(y,p.y));}
cp operator-(const cp &p)const{return cp(dec(x,p.x),dec(y,p.y));}
cp operator*(const cp &p)const{return cp(dec(mul(x,p.x),mul(y,p.y)),dec(add(mul(x,p.y),mul(p.x,y)),mul(y,p.y)));}
void operator+=(const cp &p){*this=*this+p;}
void operator-=(const cp &p){*this=*this-p;}
void operator*=(const cp &p){*this=*this*p;}
};
const cp om[]={cp(1,0),cp(0,1),cp(mo-1,mo-1)};
int n,m,ans,ex[M],ey[M],ew[M];
cp a[N][N];
cp calc()
{
cp ret=cp(1,0);
for(int l=1;l<n;l++)
{
int e=0;for(int i=l;i<n;i++)if(a[i][l]){e=i;break;}
if(!e) return cp(0,0);
if(e!=l){ret=cp(0,0)-ret;for(int j=1;j<n;j++) swap(a[l][j],a[e][j]);}
cp inv=a[l][l].inv();
for(int i=l+1;i<n;i++)
{
cp k=a[i][l]*inv;
for(int j=l;j<n;j++) a[i][j]-=k*a[l][j];
}
ret*=a[l][l];
}return ret;
}
int main()
{
freopen("sum.in","r",stdin),freopen("sum.out","w",stdout);
read(n,m);for(int i=1;i<=m;i++) read(ex[i],ey[i],ew[i]);
for(int p=1;p<C;p*=3)
{
static cp at[3];
static cp w,x,y;
for(int i=0;i<3;i++)
{
memset(a,0,sizeof(a));
for(int j=1;j<=m;j++)
{
w=om[(i*((ew[j]/p)%3))%3];
a[ex[j]][ex[j]]+=w,a[ey[j]][ey[j]]+=w;
a[ex[j]][ey[j]]-=w,a[ey[j]][ex[j]]-=w;
}at[i]=calc();
}
x=at[0]+at[1]*om[2]+at[2]*om[1],y=at[0]+at[1]*om[1]+at[2]*om[2];
doadd(ans,mul(p,add(x.x,add(y.x,y.x))));
}
domul(ans,inv3);
printf("%d\n",ans);
return 0;
}
}
int main(){return RKK::main();}
loj6271 「长乐集训 2017 Day10」生成树求和 加强版(矩阵树定理,循环卷积)的更多相关文章
- loj6271「长乐集训 2017 Day10」生成树求和 加强版
又是一个矩阵树套多项式的好题. 这里我们可以对每一位单独做矩阵树,但是矩阵树求的是边权积的和,而这里我们是要求加法,于是我们i将加法转化为多项式的乘法,其实这里相当于一个生成函数?之后如果我们暴力做的 ...
- LOJ#6271. 「长乐集训 2017 Day10」生成树求和 加强版
传送门 由于是边权三进制不进位的相加,那么可以考虑每一位的贡献 对于每一位,生成树的边权相当于是做模 \(3\) 意义下的加法 考虑最后每一种边权的生成树个数,这个可以直接用生成函数,在矩阵树求解的时 ...
- 「长乐集训 2017 Day10」划分序列 (二分 dp)
「长乐集训 2017 Day10」划分序列 题目描述 给定一个长度为 n nn 的序列 Ai A_iAi,现在要求把这个序列分成恰好 K KK 段,(每一段是一个连续子序列,且每个元素恰好属于一 ...
- 「长乐集训 2017 Day8」修路 (斯坦纳树)
题目描述 村子间的小路年久失修,为了保障村子之间的往来,AAA君决定带领大家修路. 村子可以看做是一个边带权的无向图GGG, GGG 由 nnn 个点与 mmm 条边组成,图中的点从 1∼n1 \si ...
- 「长乐集训 2017 Day1」区间 线段树
题目 对于两个区间\((a,b),(c,d)\),若\(c < a < d\)或\(c < b < d\)则可以从\((a,b)\)走到\((c,d)\)去,现在有以下两种操作 ...
- 「6月雅礼集训 2017 Day10」quote
[题目大意] 一个合法的引号序列是空串:如果引号序列合法,那么在两边加上同一个引号也合法:或是把两个合法的引号序列拼起来也是合法的. 求长度为$n$,字符集大小为$k$的合法引号序列的个数.多组数据. ...
- LOJ#6049. 「雅礼集训 2017 Day10」拍苍蝇(计算几何+bitset)
题面 传送门 题解 首先可以用一个矩形去套这个多边形,那么我们只要枚举这个矩形的左下角就可以枚举完所有多边形的位置了 我们先对每一个\(x\)坐标开一个\(bitset\),表示这个\(x\)坐标里哪 ...
- LOJ#6047. 「雅礼集训 2017 Day10」决斗(set)
题面 传送门 题解 这么简单一道题我考试的时候居然只打了\(40\)分暴力? 如果我们把每个点的\(a_i\)记为\(deg_i-1\),其中\(deg_i\)表示有\(deg_i\)个数的\(A_i ...
- LOJ#6048. 「雅礼集训 2017 Day10」数列(线段树)
题面 传送门 题解 我的做法似乎非常复杂啊-- 首先最长上升子序列长度就等于把它反过来再接到前面求一遍,比方说把\(2134\)变成\(43122134\),实际上变化之后的求一个最长上升子序列和方案 ...
随机推荐
- ConcurrentHashMap (jdk1.7)源码学习
一.介绍 1.Segment(分段锁) 1.1 Segment 容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并 ...
- Windows查看本机SSH公钥,生成公钥
#Windows查看本机**SSH**公钥,生成公钥<br>--- ### 1.查看 ssh 公钥方法: 1. 打开你的 git bash 窗口 2. 进入 .ssh 目录:cd ~/.s ...
- JMM之Java中锁概念的分类总结
在Java的并发编程中不可避免的涉及到锁.从不同维护可以将锁进行不同的分类,如下: 1.乐观锁和悲观锁(根据读写操作的比例划分) 乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数 ...
- ASP.NET Core 6框架揭秘实例演示[07]:文件系统
ASP.NET Core应用具有很多读取文件的场景,如读取配置文件.静态Web资源文件(如CSS.JavaScript和图片文件等).MVC应用的视图文件,以及直接编译到程序集中的内嵌资源文件.这些文 ...
- Selenium自动化测试面试题合集
1.什么是自动化测试.自动化测试的优势是什么? 通过工具或脚本代替手工测试执行过程的测试都叫自动化测试. 自动化测试的优势: 1.减少回归测试成本 2.减少兼容性测试成本 3.提高测试反馈速度 4.提 ...
- 快速搭建一套k8s集群环境
参考官网 kubeadm是官方提供的快速搭建k8s集群的开源工具,对于非运维人员学习k8s,kubeadm方式安装相对更简单. kubeadm创建一个集群:https://kubernetes.io/ ...
- 学习OMO游戏管理驾驶舱的设计
2019年第1季度,Smartbi帮助合作伙伴开发了一个销售管理沙盘游戏(OMO),在第一个版本中主要精力放在游戏的后台过程逻辑上(基于电子表格的报表和回写能力),并没有把Smartbi的最强项--数 ...
- C# 属性(一)
C# 中的属性是特殊的方法,该方法只负责对私有字段经行的操作,.我们用反编译查看时候看到真实属性是带()的方法,里面还包含get()和set()方法. 属性完成对私有字段的封装.对类的外部用户来说,属 ...
- ssh静态代理模式讲解与使用
--作者:飞翔的小胖猪 --创建时间:2021年5月18日 --修改时间:2021年5月23日 一.说明 SSH 为建立在应用层基础上的安全协议.SSH 是较可靠专为远程登录会话和其他网络服务提供安全 ...
- JavaWeb-前端基础
前端基础 前端:我们网站的页面,包括网站的样式.图片.视频等一切用户可见的内容都是前端的内容. 后端:处理网站的所有数据来源,比如我们之前从数据库中查询数据,而我们查询的数据经过处理最终会被展示到前端 ...