【题解】#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT)
【题解】#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT)
之前做这道题不理解,有一点走火入魔了,甚至想要一本近世代数来看,然后通过人类智慧思考后发现,这道理可以用打马后炮别的方式来理解。
先放松一点条件,假如位运算只有一种,定位某一颗生成树,那么可以知道
\]
写成生成函数的形式,对于每条边就是
\]
现在重边可以看做一条边了
那么可以知道
\]
很显然,我们对\(h(x)\)做FWT,就得到了\(H(x)\)
\]
其中\(*\)表示点积。
考虑这个FWT函数的每一位,它都是由点积而来的,也就是说第x位上H(T)数组的最终值和其他位置上的值无关。
那么我们对每条边做一个FWT后,每两个点之间有一个\(2^w\)次方大小的数组(w是题目里的w),对于每一个值都做一遍Matrix Tree,得到了一个值\(c_w\)。
根据Matrix Tree的原理,这就相当于\(O({m\choose n-1})\)地枚举边集,然后再将每条边的边权(一个生成函数做沃氏变换后变成的生成函数)相乘求和。显然就有了\(H=C\)。
还有一个问题是题目给定的鬼畜的运算,有个东西叫做扩展FWT,具体做法是对于每一位判断一下是哪个运算,然后直接按照对应的运算法则算就行。正确性可能显然?
于是这道题就完成了
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<assert.h>
#include<vector>
using namespace std;  typedef long long ll;
inline int qr(){
	int ret=0,f=0,c=getchar();
	while(!isdigit(c))f|=c==45,c=getchar();
	while(isdigit(c)) ret=ret*10+c-48,c=getchar();
	return f?-ret:ret;
}
const int mod=998244353;
const int gi=(mod+1)/3;
const int g=3;
const int inv2=(mod+1)>>1;
const int maxn=13;
int n,m,ty[1<<maxn],w;
char C[maxn];
typedef vector<int> poly;
poly Mat[75][75],a[71];
inline int MOD(const int&x){return x>=mod?x-mod:x;}
inline int MOD(const int&x,const int&y){return 1ll*x*y%mod;}
inline int ksm(const int&ba,const int&p){
	int ret=1;
	for(int t=p,b=ba%mod;t;t>>=1,b=MOD(b,b))
		if(t&1) ret=MOD(ret,b);
	return ret;
}
inline int inv(int x){return ksm(x,mod-2);}
void FWT(poly&a,int op){
	int len=a.size();
	for(int t=1,c=0;t<len;t<<=1,++c)
		for(int i=0;i<len;i+=t<<1)
			for(int j=0;j<t;++j)
				if(ty[c]==0) a[i+j+t]=MOD(a[i+j+t]+MOD(op,a[i+j]));
				else if(ty[c]==1) a[i+j]=MOD(a[i+j]+MOD(op,a[i+j+t]));
				else {
					int t0=a[i+j],t1=a[i+j+t];
					a[i+j]=MOD(t0+t1),a[i+j+t]=MOD(t0-t1+mod);
					if(op!=1) a[i+j]=MOD(a[i+j],inv2),a[i+j+t]=MOD(a[i+j+t],inv2);
				}
}
poly operator + (poly a,poly b){
	a.resize(max(a.size(),b.size()));
	for(int t=0,ed=b.size();t<ed;++t) a[t]=MOD(a[t]+b[t]);
	return a;
}
poly operator *(int a,poly b){
	for(auto&t:b) t=MOD(t,a);
	return b;
}
void Gauss(){
	int sav=1;
	for(int t=1;t<n;++t){
		for(int i=t+1;i<n&&!a[t][t];++i)
			if(a[i][t]) sav=mod-sav,swap(a[t],a[i]);
		if(!a[t][t]) return;
		sav=MOD(sav,a[t][t]);
		for(int k=1,v=inv(a[t][t]);k<n;++k)
			a[t][k]=MOD(a[t][k],v);
		for(int i=t+1;i<n;++i)
			if(a[i][t])
				for(int k=1,v=inv(a[i][t]);k<n;++k)
					a[i][k]=MOD(a[i][k]-MOD(v,a[t][k])+mod);
	}
	a[1][1]=MOD(sav,a[1][1]);
}
int main(){
	n=qr(); m=qr();
	scanf("%s",C);
	w=strlen(C);
	for(int t=0;t<w;++t) ty[t]=C[t]=='&'?1:C[t]=='|'?2:3;
	for(int t=1;t<=n;++t)
		for(int i=1;i<=n;++i)
			Mat[t][i].resize(1<<w);
	for(int t=1,a,b,v;t<=m;++t){
		a=qr(),b=qr(),v=qr();
		Mat[a][b][v]=MOD(Mat[a][b][v]-1+mod);
		Mat[b][a][v]=MOD(Mat[b][a][v]-1+mod);
		Mat[a][a][v]=MOD(Mat[a][a][v]+1);
		Mat[b][b][v]=MOD(Mat[b][b][v]+1);
	}
	for(int t=1;t<n;++t)
		for(int i=1;i<n;++i)
			FWT(Mat[t][i],1);
	for(int t=1;t<n;++t) a[t].resize(n);
	poly ret(1<<w);
	for(int k=0;k<1<<w;++k){
		for(int t=1;t<n;++t)
			for(int i=1;i<n;++i)
				a[t][i]=Mat[t][i][k];
		Gauss(); ret[k]=1;
		for(int t=1;t<n;++t) ret[k]=MOD(ret[k],a[t][t]);
	}
	FWT(ret,-1);
	int ans=-1;
	for(int t=0;t<1<<w;++t)
		if(ret[t]) ans=t;
	printf("%d\n",ans);
	return 0;
}
												
											【题解】#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT)的更多相关文章
- 「WC 2019」数树
		
「WC 2019」数树 一道涨姿势的EGF好题,官方题解我并没有完全看懂,尝试用指数型生成函数和组合意义的角度推了一波.考场上只得了 44 分也暴露了我在数数的一些基本套路上的不足,后面的 \(\ex ...
 - 【LOJ6620】「THUPC 2019」不等式 / inequality(线段树)
		
点此看题面 大致题意: 给你两个长度为\(n\)的数组\(a_i\)和\(b_i\),定义\(f_k(x)=\sum_{i=1}^k|a_ix+b_i|\),对于\(k=1\sim n\)的每个\(f ...
 - 「THUPC 2019」不等式 / inequality
		
https://loj.ac/problem/6620 高中数学好题.. |kx+b|的函数图像很直观,直接考虑函数图像: 一定只有一段极小值点! 这个点就是最小值了 特点:斜率为0! 而且发现,如果 ...
 - 「CSP-S 2019」括号树
		
[题目描述] 传送门 [题解] 是时候讨论一下我在考场上是怎么将这道题写挂的了 初看这道题毫无思路,先看看部分分吧 一条链的情况?设k[i]表示前i个括号的方案数 显然\(k[i]=k[i-1]+\) ...
 - #3146. 「APIO 2019」路灯
		
#3146. 「APIO 2019」路灯 题目描述 一辆自动驾驶的出租车正在 Innopolis 的街道上行驶.该街道上有 \(n + 1\) 个停车站点,它们将街道划分成了 \(n\) 条路段.每一 ...
 - LOJ#3054. 「HNOI 2019」鱼
		
LOJ#3054. 「HNOI 2019」鱼 https://loj.ac/problem/3054 题意 平面上有n个点,问能组成几个六个点的鱼.(n<=1000) 分析 鱼题,劲啊. 容易想 ...
 - [Luogu 3701] 「伪模板」主席树
		
[Luogu 3701] 「伪模板」主席树 这是一道网络流,不是主席树,不是什么数据结构,而是网络流. 题目背景及描述都非常的暴力,以至于 Capella 在做此题的过程中不禁感到生命流逝. S 向 ...
 - #3145. 「APIO 2019」桥梁
		
#3145. 「APIO 2019」桥梁 题目描述 圣彼得堡市内所有水路长度总和约 282 千米,市内水域面积占城市面积的 7%.--来自维基百科 圣彼得堡位于由 \(m\) 座桥梁连接而成的 \(n ...
 - #3144. 「APIO 2019」奇怪装置
		
#3144. 「APIO 2019」奇怪装置 题目描述 考古学家发现古代文明留下了一种奇怪的装置.该装置包含两个屏幕,分别显示两个整数 \(x\) 和 \(y\). 经过研究,科学家对该装置得出了一个 ...
 
随机推荐
- sqlserver 序号重新计算
			
DBCC CHECKIDENT('leshua_TradeData',NORESEED) DBCC CHECKIDENT('表名',NORESEED)
 - 《attention is all you need》解读
			
Motivation: 靠attention机制,不使用rnn和cnn,并行度高 通过attention,抓长距离依赖关系比rnn强 创新点: 通过self-attention,自己和自己做atten ...
 - CCPC final Cockroaches
			
算法假了,我想的是通过枚举x,删除y的影响,这样答案第一个是没有任何问题的,但是第二个会算重复. 因为我枚举每一个x的时候,得到的y,而算另外一个x的时候,可能已经通过其他的点选到了这个点y这就有点麻 ...
 - TP-admin即基于ThinkPHP5拿来即用高性能后台管理系统
			
TP-Admin即基于ThinkPHP5的web后台管理系统(总结一套自己的后台管理系统,方便自己后续的项目开发.) 主要特性:自适应手机端.支持国际化.吸取其他CMF框架优点.多站点部署.日志记录. ...
 - Unity5.6.4f1 配置WebGL教程
			
Unity 5.6.4f1 发布WebGL的配置教程 步骤一:先查看自带的Unity是否yi配置好WebGL的项,若无,则可遵循以下教程来设置 步骤二:下图是我已经设置好的,未设置好的状态是,有个Op ...
 - ThinkPHP URL 路由简介
			
简单的说,URL 路由就是允许你在一定规则下定制你需要的 URL 样子,以达到美化 URL ,提高用户体验,也有益于搜索引擎收录的目的. 例子 原本的 URL 为: http://www.5idev. ...
 - laravel5.*安装使用Redis以及解决Class 'Predis\Client' not found和Fatal error: Non-static method Redis::set() cannot be called statically错误
			
https://phpartisan.cn/news/35.html laravel中我们可以很简单的使用Redis,如何在服务器安装Redis以及原创访问你们可以访问Ubuntu 设置Redis密码 ...
 - java基本数据类型和包装类相互转换
			
把基本数据类型 → 包装类: 通过对应包装类的构造方法实现 除了Character外,其他包装类都可以传入一个字符串参数构建包装类对象. 包装类 → 基本数据类型 包装类的实例方法xxxValue() ...
 - 【codeforces 761D】Dasha and Very Difficult Problem
			
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
 - JS开发常用工具函数 总结
			
js原生工具库 1.isStatic:检测数据是不是除了symbol外的原始数据 */ function isStatic(value) { return( typeof value === 'str ...