【loj6496「雅礼集训 2018 Day1」仙人掌 】
要期末考试了,感觉这一学期就这样水过去了,自己还是这么地菜,,,emmmm.....偶然去了趟晚自习,那笑容真甜owo
题目描述
给出一张$n$个点$m$条边的无向连通图,其中每条边至多属于一个简单环,保证没有自环,可能有重边。你需要为其中每条边定向,其中第$i$个点的出度不能超过$a_i$求方案数。输入格式
第一行包括两个正整数$n$,$m$接下来 $m$行,每行两个正整数,表示有一条边连接这两个点。 最后一行$n$个正整数,其中第 $i$ 个表示 $a_{i}$输出格式
输出一个非负整数,表示答案对 $998244353$取模后的结果。样例
样例输入 1
3 4 1 2 2 1 2 3 3 2 1 2 3样例输出 1
7 对于全部数据 $1≤ai≤n≤10^5,1≤m≤2×10^5$ 嗯,少有的一道题目的算法真的和题目名字般配的一道题。 根据hdhd大神的描述,他似乎直接秒了,并且觉得很水,,一定是我太菜了,只想到了树的情况,怎么都没想好环的处理方式。果然仙人掌还是没有学好呢。 题意很显然。对于树的情况也比较显然f[x][0/1]表示向父亲边是否有出度,最后答案f[1][0] $f[x][k] = \sum\limits_{k_{1}+k_{2}+...k_{v}<=k}f[x][k_{v}] (v\in x_{son}) $ 分治ntt即可。 那么环怎么办? 我们给dp改为f[x][0/1/2]为了处理可能在环上向两边连边的情况。 假设我们顺时针枚举,我们枚举换上第一条边选了没有,g[x][0/1]表示在环上往逆时针一条边是否有出度。之后直接转移就可以了。#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn = 4e5+5;
const int mod = 998244353;
typedef vector<int> ve;
int add(int x,int y) { x+=y; return x>=mod?x-mod:x; }
int sub(int x,int y) { x-=y; return x<0?x+mod:x; }
int mul(int x,int y) { return 1ll*x*y%mod; }
int ksm(int a,int b) {
int ans = 1;
for(;b;b>>=1,a=mul(a,a))
if(b&1) ans = mul(ans,a);
return ans;
}
int n,m,tot;
struct edge{
int en[maxn],nt[maxn],la[maxn],owo;
void adg(int x,int y) {
en[++owo]=y; nt[owo]=la[x]; la[x]=owo;
}
}V,G;
int low[maxn],dfn[maxn],dfx;
int sta[maxn],top;
void tarjan(int x,int ba) {
dfn[x] = low[x] = ++dfx;
sta[++top] = x;
for(int it=V.la[x];it;it=V.nt[it]) {
int y = V.en[it];
if( (it^1)==ba) continue;
if(!dfn[y]) {
tarjan(y,it);
low[x] = min(low[x],low[y]);
if(low[y]>dfn[x]) G.adg(x,y),top--;
else if(low[y]==dfn[x]) {
++tot; G.adg(x,tot);
int o;
do{
o = sta[top--];
G.adg(tot,o);
}while(o!=y);
}
} else low[x] = min(low[x],dfn[y]);
}
}
int A[maxn];
int f[maxn][3];
int g[maxn][2];
int ta[maxn<<1],tb[maxn<<1];
void ntt(int *a,int s,int dft){
for(int i=0,j=0;i<s;i++) {
if(i<j) swap(a[i],a[j]);
for(int k=(s>>1);(j^=k)<k;k>>=1);
}
for(int st=1;st<s;st<<=1) {
int dwg; dwg= ( dft==1 ? ksm(3,(mod-1)/(st<<1)) : ksm(3,(mod-1)-(mod-1)/(st<<1) ) );
for(int i=0;i<s;i+=(st<<1)) {
int ng = 1;
for(int j=i;j<i+st;j++) {
int x = a[j]; int y = mul(a[j+st],ng);
ng = mul(dwg,ng);
a[j] = add(x,y); a[j+st] = sub(x,y);
}
}
}
if(dft==1) return;
int invs = ksm(s,mod-2);
for(int i=0;i<s;i++) a[i] = mul(a[i],invs);
}
int tt;
ve PL[maxn];
void MUL(ve&o,ve&x,ve&y) {
int OO = x.size() + y.size() - 2;
int len = 1;
for(;len<=OO;len<<=1);
fill(ta,ta+len,0);
fill(tb,tb+len,0);
for(int i=x.size()-1;i>=0;i--) ta[i] = x[i];
for(int i=y.size()-1;i>=0;i--) tb[i] = y[i];
ntt(ta,len,1); ntt(tb,len,1);
for(int i=0;i<len;i++) ta[i] = mul(ta[i],tb[i]);
ntt(ta,len,-1);
o.resize(OO+1);
for(int i=0;i<=OO;i++) o[i] = ta[i];
y.clear();
}
void EZ(int l,int r) {
if(l==r) return;
int mid = (l+r)>>1;
EZ(l,mid); EZ(mid+1,r);
MUL(PL[l],PL[l],PL[mid+1]);
return;
}
void dfs(int x) {
for(int it=G.la[x];it;it=G.nt[it]) {
int y = G.en[it];
dfs(y);
}
if(x<=n) {
if(!G.la[x]) {
f[x][0] = 1;
if(A[x]>=1) f[x][1] = 1;
if(A[x]>=2) f[x][2] = 1;
return;
}
tt = 0;
for(int it=G.la[x];it;it=G.nt[it]) {
int y = G.en[it];
++tt; if(y>n) {
PL[tt].resize(3); PL[tt][2] = f[y][0]; PL[tt][1] = f[y][1]; PL[tt][0] = f[y][2];
} else {
PL[tt].resize(2); PL[tt][1] = f[y][0]; PL[tt][0] = f[y][1];
}
}
EZ(1,tt);
PL[1].resize(A[x]+1);
for(int i=1;i<=A[x];i++) PL[1][i] = add(PL[1][i],PL[1][i-1]);
f[x][0] = PL[1][A[x]];
if(A[x]>=1) f[x][1] = PL[1][A[x]-1];
if(A[x]>=2) f[x][2] = PL[1][A[x]-2];
return;
} else {
for(int mj=0;mj<=1;mj++) {
int oo = 1;
g[oo][mj] = 1; g[oo][mj^1] = 0;
for(int it=G.la[x];it;it=G.nt[it]) {
++oo; int y = G.en[it];
g[oo][0] = add( mul(g[oo-1][0],f[y][1] ) , mul(g[oo-1][1],f[y][2]) );
g[oo][1] = add( mul(g[oo-1][0],f[y][0]) , mul(g[oo-1][1],f[y][1] ) );
}
f[x][mj+1] = add(f[x][mj+1],g[oo][0]);
f[x][mj] = add(f[x][mj],g[oo][1]);
}
return;
}
}
int main() {
// freopen("ccc.in","r",stdin);
V.owo = 1;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
int x,y; scanf("%d%d",&x,&y);
V.adg(x,y); V.adg(y,x);
}
for(int i=1;i<=n;i++) scanf("%d",&A[i]);
tot = n; tarjan(1,0); dfs(1);
//cerr<<f[5][2]<<endl;
printf("%d",f[1][0]);
}