一、题目

点此看题

二、解法

这道题很离谱啊,看上去是求一个最大值,其实是把生成树权值为 \(i\) 的个数都给算出来,因为权值很小。

既然是生成树可以考虑矩阵树定理,我们考虑他是求这样一个式子:

\[\sum\prod e_{w_i}
\]

对于这个乘法的理解是很灵活的,只要他能满足直接点值相乘就可以了,比如把边权换成一次多项式来做加法(就是 \(2020\) 年的联合省选题),而这道题是 \(\tt FWT\) 后做矩阵树定理,因为它满足点值相乘。

具体说来,也就是先求出只考虑边权为 \(v\) 的边的矩阵 \(mp[i][j][v]\) ,然后对每个 \(mp[i][j]\) 做 \(\tt FWT\) ,这里的 \(\tt FWT\) 要魔改一下,因为是每一位是独立的,所以每一位做一种 \(\tt FWT\) 是可以的(比如这一位是或运算就做或 \(\tt FWT\))

现在就满足点值相乘了,我们求出每个边权的行列式 \(c[v]\) ,然后对 \(c\) 做同样的 \(\tt IFWT\) ,就得到了每个边权的方案数了。注意我们要一直让所有权值为正才行。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MOD = 1e9+7;
const int N = 75;
const int M = 4100;
#define int long long
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,w,lim,inv,a[N][N][M],r[N][N],c[M];char s[M];
int qkpow(int a,int b)
{
int r=1;
while(b>0)
{
if(b&1) r=r*a%MOD;
a=a*a%MOD;
b>>=1;
}
return r;
}
void fwt(int *a,int n,int op)
{
for(int i=1,b=0;i<n;i<<=1,b++)
{
int p=i<<1;
if(s[b]=='|')
{
for(int j=0;j<n;j+=p)
for(int k=0;k<i;k++)
{
if(op==1) a[i+j+k]=(a[i+j+k]+a[j+k])%MOD;
else a[i+j+k]=(a[i+j+k]-a[j+k]+MOD)%MOD;
}
}
if(s[b]=='&')
{
for(int j=0;j<n;j+=p)
for(int k=0;k<i;k++)
{
if(op==1) a[j+k]=(a[i+j+k]+a[j+k])%MOD;
else a[j+k]=(a[j+k]-a[i+j+k]+MOD)%MOD;
}
}
if(s[b]=='^')
{
for(int j=0;j<n;j+=p)
for(int k=0;k<i;k++)
{
int x=a[j+k],y=a[i+j+k];
a[j+k]=(x+y)%MOD;
a[i+j+k]=(x-y+MOD)%MOD;
if(op==-1)
{
a[j+k]=a[j+k]*inv%MOD;
a[i+j+k]=a[i+j+k]*inv%MOD;
}
}
}
}
}
int zy()
{
int ans=1;
for(int i=1;i<n;i++)
{
for(int j=i+1;j<n;j++)
if(!r[i][i] && r[j][i])
{
ans=MOD-ans;//手误了
swap(r[i],r[j]);
break;
}
if(!r[i][i]) return 0;
int iv=qkpow(r[i][i],MOD-2);
for(int j=i+1;j<n;j++)
{
int t=r[j][i]*iv%MOD;
for(int k=i;k<n;k++)
r[j][k]=(r[j][k]-t*r[i][k]%MOD+MOD)%MOD;
}
ans=ans*r[i][i]%MOD;
}
return ans;
}
signed main()
{
n=read();m=read();inv=(MOD+1)/2;
scanf("%s",s);w=strlen(s);lim=1<<w;
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),c=read();
a[u][v][c]=(a[u][v][c]+MOD-1)%MOD;
a[v][u][c]=(a[v][u][c]+MOD-1)%MOD;
a[u][u][c]++;a[v][v][c]++;
}
for(int i=1;i<n;i++)
for(int j=1;j<n;j++)
fwt(a[i][j],lim,1);
for(int i=0;i<lim;i++)
{
memset(r,0,sizeof r);
for(int j=1;j<n;j++)
for(int k=1;k<n;k++)
r[j][k]=a[j][k][i];
c[i]=zy();
}
fwt(c,lim,-1);
for(int i=lim-1;i>=0;i--)
if(c[i]>0)
{
printf("%lld\n",i);
return 0;
}
puts("-1");
}

[THUPC2019] 找树的更多相关文章

  1. 洛谷 P5406 - [THUPC2019]找树(FWT+矩阵树定理)

    题面传送门 首先看到这道题你必须要有一个很清楚的认识:这题新定义的 \(\oplus\) 符号非常奇怪,也没有什么性质而言,因此无法通过解决最优化问题的思路来解决这个问题,只好按照计数题的思路来解决, ...

  2. poj 1655 Balancing Act(找树的重心)

    Balancing Act POJ - 1655 题意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的. /* 找树的重心可以用树形dp或 ...

  3. Leetcode之深度优先搜索(DFS)专题-513. 找树左下角的值(Find Bottom Left Tree Value)

    Leetcode之深度优先搜索(DFS)专题-513. 找树左下角的值(Find Bottom Left Tree Value) 深度优先搜索的解题详细介绍,点击 给定一个二叉树,在树的最后一行找到最 ...

  4. LeetCode 513. 找树左下角的值(Find Bottom Left Tree Value)

    513. 找树左下角的值 513. Find Bottom Left Tree Value 题目描述 给定一个二叉树,在树的最后一行找到最左边的值. LeetCode513. Find Bottom ...

  5. 【题解】#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT)

    [题解]#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT) 之前做这道题不理解,有一点走火入魔了,甚至想要一本近世代数来看,然后通过人类智慧思考后发现, ...

  6. Java实现 LeetCode 513 找树左下角的值

    513. 找树左下角的值 给定一个二叉树,在树的最后一行找到最左边的值. 示例 1: 输入: 2 / \ 1 3 输出: 1 示例 2: 输入: 1 / \ 2 3 / / \ 4 5 6 / 7 输 ...

  7. 1090 Highest Price in Supply Chain (25 分)(模拟建树,找树的深度)牛客网过,pat没过

    A supply chain is a network of retailers(零售商), distributors(经销商), and suppliers(供应商)-- everyone invo ...

  8. Codeforces Beta Round #87 (Div. 2 Only)-Party(DFS找树的深度)

    A company has n employees numbered from 1 to n. Each employee either has no immediate manager or exa ...

  9. poj 1655 找树的重心

    树形DP 求树的重心,即选择一个结点删去,使得分出的 若干棵树的结点数 的最大值最小 #include<map> #include<set> #include<cmath ...

随机推荐

  1. Redis的主从架构+哨兵模式

    Redis主从架构 redis主从架构搭建,配置从节点步骤: 1.复制一份redis.conf文件的目录 cd /usr/local/java cp -a redis redis_6380 2.将相关 ...

  2. Redis 穿透 & 击穿 & 雪崩

    原文:https://www.cnblogs.com/binghe001/p/13661381.html 缓存穿透 如果在请求数据时,在缓存层和数据库层都没有找到符合条件的数据,也就是说,在缓存层和数 ...

  3. Leetcode(877)-石子游戏

    亚历克斯和李用几堆石子在做游戏.偶数堆石子排成一行,每堆都有正整数颗石子 piles[i] . 游戏以谁手中的石子最多来决出胜负.石子的总数是奇数,所以没有平局. 亚历克斯和李轮流进行,亚历克斯先开始 ...

  4. Splunk监控软件操作

    一.  Splunk公司与产品 美国Splunk公司,成立于2004年,2012年纳斯达克上市,第一家大数据上市公司,荣获众多奖项和殊荣.总部位于美国旧金山,伦敦为国际总部,香港设有亚太支持中心,上海 ...

  5. confirm() :带有指定消息和 OK 及取消按钮的对话框

    定义和用法 confirm() 方法用于显示一个带有指定消息和 OK 及取消按钮的对话框. 语法 confirm(message) 参数描述 message 要在 window 上弹出的对话框中显示的 ...

  6. codevs1039整数的k划分-思考如何去重复

    题目描述将整数n分成k份,且每份不能为空,任意两种划分方案不能相同(不考虑顺序).例如:n=7,k=3,下面三种划分方案被认为是相同的.1 1 51 5 15 1 1问有多少种不同的分法.输入描述输入 ...

  7. CSS pseudo element All In One

    CSS pseudo element All In One CSS 伪元素 https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elemen ...

  8. Flutter Widgets

    Flutter Widgets Flutter 组件 Syncfusion Flutter Widgets 所有组件均支持即装即用的 Android,iOS和 Web not free https:/ ...

  9. css & circle & shapes

    css & circle & shapes css-tricks circle https://css-tricks.com/the-shapes-of-css/ https://cs ...

  10. npm & private npm service & nrm & nvm

    npm & private npm service & nrm & nvm npm server # nrm https://www.cnblogs.com/xgqfrms/t ...