【LOJ】#2496. 「AHOI / HNOI2018」毒瘤
还有这么诚实的出题人!
我们最多影响20个点,然后把这20个点的虚树建出来,并且枚举每个点的选举状态,如果一个点选或不选可以通过改\(dp[u][0] = 0\)或\(dp[u][1] = 0\)完成
状态应该不多,因为每条边只有三种选的情况,上限是\(3^{m - n + 1}\)的
然后我们考虑递推出\(dp[u][0]\)和\(dp[u][1]\)在更新它虚树上的父亲的方案数,是可以用\(k_0 * dp[u][0] + k_1 * dp[u][1]\)表示的,这个可以递推出来
然后就剩别把代码敲错了= =
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
#define eps 1e-8
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
const int MOD = 998244353;
int N,M;
struct node {
int to,next;
}E[MAXN * 2];
int head[MAXN],sumE,belong[MAXN],dfn[MAXN],idx,aux[MAXN],faAux[MAXN],acnt,tot,fa[MAXN][20],dep[MAXN];
int sta[MAXN],top,dp[MAXN][2],g[MAXN][2][2],val[MAXN][2],id[MAXN],Ncnt,qa[MAXN][2];
pii p[MAXN];
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
int fpow(int x,int c) {
int res = 1,t = x;
while(c) {
if(c & 1) res = mul(res,t);
t = mul(t,t);
c >>= 1;
}
return res;
}
void update(int &x,int y) {
x = inc(x,y);
}
int getbl(int x) {
return belong[x] == x ? x : belong[x] = getbl(belong[x]);
}
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
bool cmp(int a,int b) {
return dfn[a] < dfn[b];
}
int dfs(int u) {
dfn[u] = ++idx;
dep[u] = dep[fa[u][0]] + 1;
dp[u][0] = dp[u][1] = 1;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u][0]) {
fa[v][0] = u;
dfs(v);
dp[u][0] = mul(dp[u][0],inc(dp[v][1],dp[v][0]));
dp[u][1] = mul(dp[u][1],dp[v][0]);
}
}
}
int lca(int u,int v) {
if(dep[u] < dep[v]) swap(u,v);
int l = 18;
while(dep[u] > dep[v]) {
if(dep[fa[u][l]] >= dep[v]) u = fa[u][l];
--l;
}
if(u == v) return u;
l = 18;
while(fa[u][0] != fa[v][0]) {
if(fa[u][l] != fa[v][l]) {
u = fa[u][l];
v = fa[v][l];
}
--l;
}
return fa[u][0];
}
void build_AuxTree() {
int t = acnt;
top = 0;
for(int i = 1 ; i <= acnt ; ++i) {
if(!top) sta[++top] = aux[i];
else {
int f = lca(aux[i],sta[top]);
while(top >= 1 && dep[sta[top]] > dep[f]) {
if(top == 1 || dep[sta[top - 1]] <= dep[f]) {
faAux[sta[top]] = f;
}
--top;
}
if(sta[top] != f) {
faAux[f] = sta[top];
sta[++top] = f;
aux[++t] = f;
}
sta[++top] = aux[i];
faAux[aux[i]] = f;
}
}
acnt = t;
sort(aux + 1,aux + acnt + 1,cmp);
if(aux[1] != 1) {faAux[aux[1]] = 1;aux[++acnt] = 1;}
sort(aux + 1,aux + acnt + 1,cmp);
for(int i = 1 ; i <= acnt ; ++i) val[aux[i]][0] = dp[aux[i]][0],val[aux[i]][1] = dp[aux[i]][1];
for(int i = acnt ; i >= 2 ; --i) {
int u = aux[i],f = faAux[u];
memset(g[u],0,sizeof(g[u]));
g[u][0][0] = 1;g[u][1][1] = 1;
while(fa[u][0] != f) {
int t = fa[u][0];
val[t][0] = mul(dp[t][0],fpow(inc(dp[u][0],dp[u][1]),MOD - 2));
val[t][1] = mul(dp[t][1],fpow(dp[u][0],MOD - 2));
memset(g[t],0,sizeof(g[t]));
g[t][0][0] = mul( inc( g[u][1][0] , g[u][0][0] ) , val[t][0]);
g[t][0][1] = mul( inc( g[u][1][1] , g[u][0][1] ) , val[t][0]);
g[t][1][0] = mul( g[u][0][0] , val[t][1]);
g[t][1][1] = mul( g[u][0][1] , val[t][1]);
u = t;
}
g[f][0][0] = inc( g[u][1][0] , g[u][0][0] );
g[f][0][1] = inc( g[u][1][1] , g[u][0][1] );
g[f][1][1] = g[u][0][1];
g[f][1][0] = g[u][0][0];
memcpy(g[aux[i]],g[f],sizeof(g[f]));
val[f][0] = mul(val[f][0],fpow(inc(dp[u][0],dp[u][1]),MOD - 2));
val[f][1] = mul(val[f][1],fpow(dp[u][0],MOD - 2));
}
}
void Init() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) belong[i] = i;
int u,v;
for(int i = 1 ; i <= M ; ++i) {
read(u);read(v);
if(getbl(u) != getbl(v)) {
belong[getbl(u)] = getbl(v);
add(u,v);add(v,u);
}
else {
p[++tot] = mp(u,v);
}
}
dfs(1);
if(M == N - 1) {
out(inc(dp[1][0],dp[1][1]));enter;
exit(0);
}
for(int j = 1 ; j <= 18 ; ++j) {
for(int i = 1 ; i <= N ; ++i) {
fa[i][j] = fa[fa[i][j - 1]][j - 1];
}
}
for(int i = 1 ; i <= tot ; ++i) {
aux[++acnt] = p[i].fi;aux[++acnt] = p[i].se;
}
sort(aux + 1,aux + acnt + 1);
acnt = unique(aux + 1,aux + acnt + 1) - aux - 1;
for(int i = 1 ; i <= acnt ; ++i) {
id[aux[i]] = ++Ncnt;
}
sort(aux + 1,aux + acnt + 1,cmp);
build_AuxTree();
}
int Calc(int S) {
for(int i = 1 ; i <= acnt ; ++i) qa[aux[i]][0] = qa[aux[i]][1] = 1;
for(int i = acnt ; i >= 1 ; --i) {
int u = aux[i];
qa[u][0] = mul( qa[u][0] , val[u][0] );
qa[u][1] = mul( qa[u][1] , val[u][1] );
if(id[u]) {
qa[u][(S >> (id[u] - 1) & 1) ^ 1] = 0;
}
if(u == 1) break;
qa[faAux[u]][0] = mul(inc( mul( g[u][0][1] , qa[u][1] ) , mul( g[u][0][0] , qa[u][0]) ) , qa[faAux[u]][0]);
qa[faAux[u]][1] = mul(inc( mul( g[u][1][1] , qa[u][1] ) , mul( g[u][1][0] , qa[u][0]) ) , qa[faAux[u]][1]);
}
return inc(qa[1][0],qa[1][1]);
}
void Solve() {
int ans = 0;
for(int S = 0 ; S < (1 << Ncnt) ; ++S) {
bool flag = 1;
for(int i = 1 ; i <= tot ; ++i) {
if((S >> (id[p[i].fi] - 1) & 1) && (S >> (id[p[i].se] - 1) & 1)) {
flag = 0;
break;
}
}
if(!flag) continue;
else update(ans,Calc(S));
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}
【LOJ】#2496. 「AHOI / HNOI2018」毒瘤的更多相关文章
- @loj - 2496@ 「AHOI / HNOI2018」毒瘤
目录 @description@ @solution@ @accepted code@ @details@ @description@ 从前有一名毒瘤. 毒瘤最近发现了量产毒瘤题的奥秘.考虑如下类型的 ...
- Loj #2495. 「AHOI / HNOI2018」转盘
Loj #2495. 「AHOI / HNOI2018」转盘 题目描述 一次小 G 和小 H 原本准备去聚餐,但由于太麻烦了于是题面简化如下: 一个转盘上有摆成一圈的 \(n\) 个物品(编号 \(1 ...
- Loj #2494. 「AHOI / HNOI2018」寻宝游戏
Loj #2494. 「AHOI / HNOI2018」寻宝游戏 题目描述 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得 ...
- loj #2510. 「AHOI / HNOI2018」道路
#2510. 「AHOI / HNOI2018」道路 题目描述 W 国的交通呈一棵树的形状.W 国一共有 n−1 个城市和 nnn 个乡村,其中城市从 111 到 n−1 编号,乡村从 111 到 n ...
- loj #2509. 「AHOI / HNOI2018」排列
#2509. 「AHOI / HNOI2018」排列 题目描述 给定 nnn 个整数 a1,a2,…,an(0≤ai≤n),以及 nnn 个整数 w1,w2,…,wn.称 a1,a2,…,an 的 ...
- loj #2508. 「AHOI / HNOI2018」游戏
#2508. 「AHOI / HNOI2018」游戏 题目描述 一次小 G 和小 H 在玩寻宝游戏,有 nnn 个房间排成一列,编号为 1,2,…,n,相邻房间之间都有 111 道门.其中一部分门上有 ...
- loj#2510. 「AHOI / HNOI2018」道路 记忆化,dp
题目链接 https://loj.ac/problem/2510 思路 f[i][a][b]表示到i时,公路个数a,铁路个数b 记忆化 复杂度=状态数=\(nlog^2n\) 代码 #include ...
- loj#2509. 「AHOI / HNOI2018」排列(思维题 set)
题意 题目链接 Sol 神仙题Orz 首先不难看出如果我们从\(a_i\)向\(i\)连一条边,我们会得到以\(0\)为根的树(因为每个点一定都有一个入度,出现环说明无解),同时在进行排列的时候需要保 ...
- loj#2020 「AHOI / HNOI2017」礼物 ntt
loj#2020 「AHOI / HNOI2017」礼物 链接 bzoj没\(letex\),差评 loj luogu 思路 最小化\(\sum\limits_1^n(a_i-b_i)^2\) 设改变 ...
随机推荐
- HGOI 20181101题解
/* 又是爆0的一天(不知道今年高考难不难,反正今天(信息学)真的难!) */ solution:对于两个数相加,有一个显然的结论就是要么不进位(相对于位数大的),要么(进最多一位) 然后对于整个数组 ...
- USACO Section 2.1 Sorting a Three-Valued Sequence 解题报告
题目 题目描述 给N个整数,每个整数只能是1,2,或3.现在需要对这个整数序列进行从小到大排序,问最少需要进行几次交换.N(1 <= N <= 1000) 样例输入 9 2 2 1 3 3 ...
- [APIO2018] New Home 新家
扫描线+线段树+二分答案+set+STL 就是把区间数颜色做得很好 时间看成线段,扫描线 对于某一个询问位置x 二分答案转化,看区间内有没有k种颜色.. 一个区间数颜色的套路是,prei上一个该颜色出 ...
- 【HDU1710】树的遍历
题目大意:给定一棵 N 个节点的二叉树的前序遍历和中序遍历,求其后序遍历. 题解:递归操作,每次只需知道先序遍历和中序遍历的开始点,左子树大小即可,根据前序遍历的开始位置可知子树根节点的坐标,再在中序 ...
- JavaScript常用模块
JavaScript常用模块 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.序列化与反序列化 JSON.stringify(obj) 序列化 JSON.parse(str) ...
- 鸟哥的Linux私房菜——第九章
视频链接,推荐看B站 土豆网:http://www.tudou.com/programs/view/XmMDbjJHJC8 B站:http://www.bilibili.com/video/av966 ...
- Java FileReader使用相对路径读取文件
Java FileReader使用相对路径读取文件 觉得有用的话,欢迎一起讨论相互学习~Follow Me 在进行编程时需要时常更换主机进行测试,如果使用绝对路径则需要经常更改,为此使用相对路径是一个 ...
- disabled属性对form表单向后台传值的影响
在form表单里,如果对input加入disabled="disabled"或disabled="true"等属性,form表单提交的时候,就不会传值到后台. ...
- bzoj千题计划267:bzoj3129: [Sdoi2013]方程
http://www.lydsy.com/JudgeOnline/problem.php?id=3129 如果没有Ai的限制,就是隔板法,C(m-1,n-1) >=Ai 的限制:m减去Ai &l ...
- '增量赋值(augmented assignment)', 多么痛的领悟!
'增量赋值(augmented assignment)', 多么痛的领悟! 深刻理解x += a 与 x = x + a 的不同: 按理说上面的两条语句是等价的, 功能上完全一样的. 之所以说不同, ...