题面传送门

首先看到这道题你必须要有一个很清楚的认识:这题新定义的 \(\oplus\) 符号非常奇怪,也没有什么性质而言,因此无法通过解决最优化问题的思路来解决这个问题,只好按照计数题的思路来解决,即考虑 \(cnt_k\) 表示权值为 \(k\) 的生成树的个数,那么我们即求最大的满足 \(cnt_k\ne 0\) 的 \(k\)。

考虑怎样维护这个东西,首先考虑一个非常 trivial 的情况,如果题目中求生成树权值的方法不是这个奇怪的 \(\oplus\) 运算而是加法怎么办。那么对于一条权值为 \(w\) 的边,如果它在生成树中,它会对生成树权值产生 \(w\) 的贡献,因此很自然地想到用幂级数表示权值,即将每条边看作一个幂级数 \(x^w\),然后跑矩阵树定理会得出一个幂级数 \(F(x)\),那么权值为 \(v\) 的生成树棵数就是 \([x^v]F(x)\)。

接下来考虑将加法换为二进制运算后怎样处理,我们还是将每条边看作一个幂级数 \(x^w\),那么与之前唯一的区别是,原来幂级数 \(x^u\) 和 \(x^v\) 乘积的贡献会累加到 \(x^{u+v}\) 上,即加法卷积,现在 \(x^u\) 和 \(x^v\) 的乘积则会累加到 \(x^{u|v}\)(或者 \(x^{u\&v}\),或 \(x^{u\operatorname{xor}v}\))上,即二进制卷积。看到二进制卷积我们很自然地想到一个东西——FWT,因此如果题目中的 \(\oplus\) 只是 \(\operatorname{and}\) 或 \(\operatorname{or}\) 或 \(\operatorname{xor}\) 的话,那么我们就可以一遍 FWT,再求出基尔霍夫矩阵解出每种权值的行列式,再 IFWT 回去求出所有的 \(cnt_k\)。而现在对于新定义的 \(\oplus\) 运算,虽然它每一位的运算规律都不同,但由于它们彼此之间互相独立,并且都是二进制运算,因此 FWT 对于该运算依然适用,具体来说对于每一位如果它是 ^ 就按照 FWTxor/IFWTxor 的套路合并,&,| 也同理,这样即可求出最终的 \(cnt_k\)。

时间复杂度 \(2^wn^3\),可以通过此题。记得模上一个大质数,为了防止冲突我取了 \(993244853\)(请求出生成树个数模 \(993244853\) 等于 \(0\) 的概率(大雾))。

const int MOD=993244853;
const int INV2=496622427;
const int MAXN=70;
const int MAXV=1<<12;
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;
}
void add(int &x,int v){((x+=v)>=MOD)&&(x-=MOD);}
int n,m,k;char s[14];
int a[MAXN+5][MAXN+5][MAXV+5],b[MAXV+5];
void FWT(int *a,int type){
for(int i=2,lg=0;lg<k;i<<=1,++lg){
for(int j=0;j<(1<<k);j+=i)
for(int l=0;l<(i>>1);l++){
if(s[lg]=='|'){
if(~type) add(a[(i>>1)+j+l],a[j+l]);
else add(a[(i>>1)+j+l],MOD-a[j+l]);
} else if(s[lg]=='&'){
if(~type) add(a[j+l],a[(i>>1)+j+l]);
else add(a[j+l],MOD-a[(i>>1)+j+l]);
} else {
int X=a[j+l],Y=a[(i>>1)+j+l];
if(~type) a[j+l]=(X+Y)%MOD,a[(i>>1)+j+l]=(X-Y+MOD)%MOD;
else a[j+l]=1ll*INV2*(X+Y)%MOD,a[(i>>1)+j+l]=1ll*INV2*(X-Y+MOD)%MOD;
}
}
}
}
int getdet(int x){
int sgn=1;
for(int i=1;i<n;i++){
int t=i;
for(int j=i+1;j<n;j++) if(a[j][i][x]) t=j;
for(int j=i;j<n;j++) swap(a[i][j][x],a[t][j][x]);
if(t^i) sgn=-sgn;
int iv=qpow(a[i][i][x],MOD-2);
for(int j=i+1;j<n;j++){
int mul=1ll*(MOD-iv)*a[j][i][x]%MOD;
for(int l=i;l<n;l++) a[j][l][x]=(a[j][l][x]+1ll*mul*a[i][l][x])%MOD;
}
} int res=(sgn+MOD)%MOD;
// for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) printf("%d%c",a[i][j][x]," \n"[j==n]);
for(int i=1;i<n;i++) res=1ll*res*a[i][i][x]%MOD;
return res;
}
int main(){
scanf("%d%d%s",&n,&m,s);k=strlen(s);
for(int i=1,u,v,w;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);--u;--v;
add(a[u][v][w],MOD-1);add(a[v][u][w],MOD-1);
add(a[u][u][w],1);add(a[v][v][w],1);
}
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) FWT(a[i][j],1);
// for(int i=0;i<(1<<k);i++){
// for(int u=1;u<n;u++) for(int v=1;v<n;v++)
// printf("%d%c",a[u][v][i]," \n"[v==n]);
// printf("\n");
// }
for(int i=0;i<(1<<k);i++) b[i]=getdet(i)/*,printf("%d\n",b[i])*/;
FWT(b,-1);for(int i=(1<<k)-1;~i;i--) if(b[i]) return printf("%d\n",i),0;
// assert(114514^1919810^114514^1919810);
puts("-1");
return 0;
}

洛谷 P5406 - [THUPC2019]找树(FWT+矩阵树定理)的更多相关文章

  1. 洛谷4208 JSOI2008最小生成树计数(矩阵树定理+高斯消元)

    qwq 这个题目真的是很好的一个题啊 qwq 其实一开始想这个题,肯定是无从下手. 首先,我们会发现,对于无向图的一个最小生成树来说,只有当存在一些边与内部的某些边权值相同的时候且能等效替代的时候,才 ...

  2. 洛谷 P3377 【模板】左偏树(可并堆)

    洛谷 P3377 [模板]左偏树(可并堆) 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或 ...

  3. 洛谷 1938 [USACO09NOV]找工就业Job Hunt

    洛谷 1938  [USACO09NOV]找工就业Job Hunt 题目描述 Bessie is running out of money and is searching for jobs. Far ...

  4. 洛谷P3412 仓鼠找$Sugar\ II$题解(期望+统计论?)

    洛谷P3412 仓鼠找\(Sugar\ II\)题解(期望+统计论?) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1327573 原题链接:洛谷P3412 ...

  5. 洛谷P3377 【模板】左偏树(可并堆) 题解

    作者:zifeiy 标签:左偏树 这篇随笔需要你在之前掌握 堆 和 二叉树 的相关知识点. 堆支持在 \(O(\log n)\) 的时间内进行插入元素.查询最值和删除最值的操作.在这里,如果最值是最小 ...

  6. 洛谷P3434 [POI2006]KRA-The Disks(线段树)

    洛谷题目传送门 \(O(n)\)的正解算法对我这个小蒟蒻真的还有点思维难度.洛谷题解里都讲得很好. 考试的时候一看到300000就直接去想各种带log的做法了,反正不怕T...... 我永远只会有最直 ...

  7. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  8. 【题解】洛谷P1350 车的放置(矩阵公式推导)

    洛谷P1350:https://www.luogu.org/problemnew/show/P1350 思路 把矩阵分为上下两块N与M 放在N中的有i辆车 则放在M中有k-i辆车 N的长为a   宽为 ...

  9. 【洛谷3822】[NOI2017] 整数(线段树压位)

    题目: 洛谷 3822 分析: 直接按题意模拟,完了. 将每次加 / 减拆成不超过 \(32\) 个对单独一位的加 / 减. 考虑给一个二进制位(下称「当前位」)加 \(1\) 时,如果这一位本来就是 ...

随机推荐

  1. 《手把手教你》系列技巧篇(三十三)-java+ selenium自动化测试-单选和多选按钮操作-上篇(详解教程)

    1.简介 在实际自动化测试过程中,我们同样也避免不了会遇到单选和多选的测试,特别是调查问卷或者是答题系统中会经常碰到.因此宏哥在这里直接分享和介绍一下,希望小伙伴或者童鞋们在以后工作中遇到可以有所帮助 ...

  2. 什么,你还使用 webpack?别人都在用 vite 搭建项目了

    一.vite 到底是干嘛的? vite 实际上就是一个面向现代浏览器,基于 ES module 实现了一个更轻快的项目构建打包工具. vite 是法语中轻快的意思. vite 的特点: 1.轻快的冷服 ...

  3. MongoDB中如何优雅地删除大量数据

    删除大量数据,无论是在哪种数据库中,都是一个普遍性的需求.除了正常的业务需求,我们需要通过这种方式来为数据库"瘦身". 为什么要"瘦身"呢? 表的数据量到达一定 ...

  4. 【Azure 应用服务】App Service For Linux 如何在 Web 应用实例上住抓取网络日志

    问题描述 在App Service For Windows的环境中,我们可以通过ArmClient 工具发送POST请求在Web应用的实例中抓取网络日志,但是在App Service For Linu ...

  5. 第五课第四周笔记3:Multi-Head Attention多头注意力

    Multi-Head Attention多头注意力 让我们进入并了解多头注意力机制. 符号变得有点复杂,但要记住的事情基本上只是你在上一个视频中学到的自我注意机制的四个大循环. 让我们看一下每次计算自 ...

  6. 关于QGIS的插件开发(C++)

    关于C++插件的开发材料较少,根据网上的指导,我采用了早期版本的插件模板生成的方法来创建QGIS的插件,其方法是从以前版本(2.18.25)里面拷贝插件模板的方法进行,具体的执行步骤为 1.拷贝文件 ...

  7. Codeforces Round #742 (Div. 2)题解

    链接 \(A,B\)题签到,就完了. \(C\)题,考虑进位时多进一位,由于是隔一位进的,所以可以发现奇数位和偶数位是相互独立的,那么我们就把奇数位和偶数位单独拉出来组成数字例如:34789,我们单独 ...

  8. python3 调用 centos 常用系统命令

    一.创建目录 1 import os 2 3 base_path = '/data/sw_backup' 4 addr= 'FT' 5 ip='192.168.1.1' 6 path = base_p ...

  9. 正则表达式之grep

    grep 的五个参数,基本的常用的: -a :将 binary 档案以 text 档案的方式搜寻数据 -c :计算找到 '搜寻字符串' 的次数 -i :忽略大小写的不同,所以大小写视为相同 -n :顺 ...

  10. 【java+selenium3】模拟键盘操作 (十二)

    一.键盘操作 用代码来模拟键盘的Enter或一系列的组合键,前面使用sendkeys()方法模拟键盘的输入,除此之外还可以模拟键盘组合键输入如下: 整理一些比较常用的键盘操作如下: sendKeys( ...