题解 画
对于 \(m=0\) 的部分赛时想了个脑瘫状压
令 \(f_{i, s}\) 为考虑到第 \(i\) 位,\(s\) 集合中的元素卡上界的方案数
转移 \(2^n\) 枚举选什么
然而这个东西有相当神奇的 \(O(n\log V)\) 做法
考虑从高到低第一个有数不压上界的位
那么低位一定可以通过调整这个数的低位使异或和等于 C,其它数可以任意选
可以对每个位 DP,令 \(f_{i, 0/1, 0/1}\) 为考虑到第 \(i\) 个数,是否有数不压上界,这些数这一位的异或和是什么的考虑低位的方案数
然后考虑带上 \(m\)
第一个想法是对边集容斥
特别注意若钦定相等形成的连通块大小为偶数需要直接贡献 \(lim+1\) 而不参与 DP
想想形成的连通块是什么就明白了
然后变为枚举点集,计算其连通导出子图的容斥系数之和
可以用全集减枚举 1 所在连通块
可以使用 \(\sum\limits_{i=0}^n(-1)^i\binom{n}{i}=[n=0]\) 来优化
然后 \(f_{s, t}\) 为已经加入了 \(s\) 中元素,它们缩成的连通块相当于 \(t\) 中的点
然后枚举补集的包含 lowbit 的子集加入貌似是 \(O(3^n)\) 的
证明咕了
点击查看代码
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
ll ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
ll lim[N], c;
int id[N], rk[N];
vector<int> to[N];
pair<int, int> e[N];
const ll mod=998244353;
// inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
inline void md(ll& a, ll b) {a=(a+b)%mod;}
namespace force{
int val[N], ans;
void dfs(int u) {
if (u>n) {
int sum=0;
for (int i=1; i<=n; ++i) sum^=val[i];
if (sum!=c) return ;
// for (int i=1; i<=m; ++i) if (val[e[i].fir]==val[e[i].sec]) return ;
++ans;
return ;
}
for (int i=0; i<=lim[u]; ++i) {
val[u]=i;
for (auto& v:to[u]) if (v<u && val[v]==val[u]) goto jump;
dfs(u+1);
jump: ;
}
}
void solve() {
dfs(1);
cout<<ans<<endl;
}
}
namespace task1{
ll f[65][1<<10], ans;
void solve() {
int lim=1<<n;
f[63][lim-1]=1;
for (int i=62; ~i; --i) {
for (int s=0,to; s<lim; ++s) if ((__builtin_popcount(s)&1?1:0)==(c&(1ll<<i)?1:0)) {
for (int t=0; t<lim; ++t) if (f[i+1][t]) {
for (int j=1; j<=n; ++j) if (t&(1<<j-1) && (((s&(1<<j-1))?1:0)>((::lim[j]&(1ll<<i))?1:0))) goto jump;
to=t;
for (int j=1; j<=n; ++j) if (t&(1<<j-1) && (((s&(1<<j-1))?1:0)<((::lim[j]&(1ll<<i))?1:0))) to^=1<<j-1;
md(f[i][to], f[i+1][t]);
// if (i==1) cout<<"add: "<<bitset<2>(s)<<' '<<bitset<2>(to)<<' '<<f[i+1][t]<<endl;
jump: ;
}
}
}
for (int s=0; s<lim; ++s) md(ans, f[0][s]);
printf("%lld\n", ans);
}
}
namespace task2{
int dsu[N], siz[N], top;
ll minn[N], sta[N], f[65][1<<6];
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void uni(int s, int t) {if ((s=find(s))!=(t=find(t))) siz[dsu[s]=t]+=siz[s];}
ll calc() {
int lim=1<<top; ll ans=0;
memset(f, 0, sizeof(f));
f[63][lim-1]=1;
for (int i=62; ~i; --i) {
for (int s=0,to; s<lim; ++s) if ((__builtin_popcount(s)&1?1:0)==(c&(1ll<<i)?1:0)) {
for (int t=0; t<lim; ++t) if (f[i+1][t]) {
for (int j=1; j<=top; ++j) if (t&(1<<j-1) && (((s&(1<<j-1))?1:0)>((sta[j]&(1ll<<i))?1:0))) goto jump;
to=t;
for (int j=1; j<=top; ++j) if (t&(1<<j-1) && (((s&(1<<j-1))?1:0)<((sta[j]&(1ll<<i))?1:0))) to^=1<<j-1;
md(f[i][to], f[i+1][t]);
jump: ;
}
}
}
for (int s=0; s<lim; ++s) md(ans, f[0][s]);
return ans;
}
void solve() {
int lim=1<<m; ll ans=0;
for (int s=0; s<lim; ++s) {
ll tem=1; top=0;
for (int i=1; i<=n; ++i) dsu[i]=i, minn[i]=::lim[i], siz[i]=1;
for (int i=1; i<=m; ++i) if (s&(1<<i-1)) uni(e[i].fir, e[i].sec);
for (int i=1; i<=n; ++i) minn[find(i)]=min(minn[find(i)], ::lim[i]);
for (int i=1; i<=n; ++i) if (find(i)==i) {
if (siz[i]&1) sta[++top]=minn[i];
else tem=tem*(minn[i]+1)%mod;
}
// cout<<"sta: "; for (int i=1; i<=top; ++i) cout<<sta[i]<<' '; cout<<endl;
ans=(ans+(__builtin_popcount(s)&1?-1:1)*tem*calc())%mod;
// cout<<"val: "<<tem*calc()<<endl;
}
printf("%lld\n", (ans%mod+mod)%mod);
}
}
namespace task3{
int dsu[N], siz[N], top;
ll minn[N], sta[N], f[16][2][2];
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void uni(int s, int t) {if ((s=find(s))!=(t=find(t))) siz[dsu[s]=t]+=siz[s];}
ll calc() {
// cout<<"calc: "<<endl;
ll ans=0;
for (int i=62; ~i; --i) {
// cout<<"i: "<<i<<endl;
int sum=0;
for (int j=1; j<=top; ++j) f[j][0][0]=f[j][0][1]=f[j][1][0]=f[j][1][1]=0;
f[0][0][0]=1;
for (int j=1; j<=top; ++j) {
ll tem=((sta[j]&((1ll<<i)-1))+1)%mod;
// cout<<"tem: "<<tem<<endl;
if (sta[j]&(1ll<<i)) {
sum^=1;
for (int k=0; k<2; ++k)
f[j][1][k]=(f[j][1][k]+f[j-1][1][k]*((1ll<<i)%mod)+f[j-1][0][k])%mod;
for (int x=0; x<2; ++x)
for (int y=0; y<2; ++y)
f[j][x][y]=(f[j][x][y]+f[j-1][x][y^1]*tem)%mod;
}
else {
for (int x=0; x<2; ++x)
for (int y=0; y<2; ++y)
f[j][x][y]=(f[j][x][y]+f[j-1][x][y]*tem)%mod;
}
}
ans=(ans+f[top][1][(c&(1ll<<i))?1:0])%mod;
if ((sum&1?1:0)!=((c&(1ll<<i))?1:0)) break;
if (i==0) ans=(ans+1)%mod;
}
// cout<<"ans: "<<ans<<endl;
return ans;
}
void solve() {
int lim=1<<m; ll ans=0;
for (int s=0; s<lim; ++s) {
ll tem=1; top=0;
for (int i=1; i<=n; ++i) dsu[i]=i, minn[i]=::lim[i], siz[i]=1;
for (int i=1; i<=m; ++i) if (s&(1<<i-1)) uni(e[i].fir, e[i].sec);
for (int i=1; i<=n; ++i) minn[find(i)]=min(minn[find(i)], ::lim[i]);
for (int i=1; i<=n; ++i) if (find(i)==i) {
if (siz[i]&1) sta[++top]=minn[i];
else tem=tem*((minn[i]+1)%mod)%mod;
}
// cout<<"sta: "; for (int i=1; i<=top; ++i) cout<<sta[i]<<' '; cout<<endl;
ans=(ans+(__builtin_popcount(s)&1?-1:1)*tem*calc())%mod;
// cout<<"val: "<<tem*calc()<<endl;
}
printf("%lld\n", (ans%mod+mod)%mod);
}
}
namespace task{
bool vis[1<<15], vis2[1<<15];
int dsu[N], siz[N], lg[1<<15], top;
ll minn[N], sta[N], f[16][2][2], g[1<<15], h[1<<15];
struct pair_hash{inline size_t operator () (const pair<int, int>& t) const {return t.fir*13131+t.sec;}};
cc_hash_table<pair<int, int>, ll, pair_hash> mp;
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void uni(int s, int t) {if ((s=find(s))!=(t=find(t))) siz[dsu[s]=t]+=siz[s];}
ll calc() {
// cout<<"calc: "<<endl;
ll ans=0;
for (int i=62; ~i; --i) {
// cout<<"i: "<<i<<endl;
int sum=0;
for (int j=1; j<=top; ++j) f[j][0][0]=f[j][0][1]=f[j][1][0]=f[j][1][1]=0;
f[0][0][0]=1;
for (int j=1; j<=top; ++j) {
ll tem=((sta[j]&((1ll<<i)-1))+1)%mod;
// cout<<"tem: "<<tem<<endl;
if (sta[j]&(1ll<<i)) {
sum^=1;
for (int k=0; k<2; ++k)
f[j][1][k]=(f[j][1][k]+f[j-1][1][k]*((1ll<<i)%mod)+f[j-1][0][k])%mod;
for (int x=0; x<2; ++x)
for (int y=0; y<2; ++y)
f[j][x][y]=(f[j][x][y]+f[j-1][x][y^1]*tem)%mod;
}
else {
for (int x=0; x<2; ++x)
for (int y=0; y<2; ++y)
f[j][x][y]=(f[j][x][y]+f[j-1][x][y]*tem)%mod;
}
}
ans=(ans+f[top][1][(c&(1ll<<i))?1:0])%mod;
if ((sum&1?1:0)!=((c&(1ll<<i))?1:0)) break;
if (i==0) ans=(ans+1)%mod;
}
// cout<<"ans: "<<ans<<endl;
return ans;
}
void solve() {
int lim=1<<n; ll ans=0;
for (int i=0; i<n; ++i) lg[1<<i]=i+1;
for (int s=0; s<lim; ++s)
for (int i=1; i<=m; ++i)
if (s&(1<<e[i].fir-1) && s&(1<<e[i].sec-1)) {vis[s]=1; break;}
for (int s=0; s<lim; ++s) {
g[s]=!vis[s];
for (int t=s; t; t=(t-1)&s) if (t!=s && t&(s&-s))
g[s]=(g[s]-g[t]*(!vis[s^t]))%mod;
}
g[0]=0;
// cout<<"g: "; for (int s=0; s<lim; ++s) cout<<g[s]<<' '; cout<<endl;
mp[{0, 0}]=1;
for (int s=0; s<lim; ++s) {
for (int k=s; ~k; k=(k-1)&s) if (!k || mp.find({s, k})!=mp.end()) {
for (int t0=(~s)&(lim-1),t=t0; t; t=(t-1)&t0) if (t&(t0&-t0)) {
if (__builtin_popcount(t)&1) md(mp[{s|t, k|(t&-t)}], mp[{s, k}]*g[t]);
else md(mp[{s|t, k}], mp[{s, k}]*g[t]%mod*((::lim[lg[t0&-t0]]+1)%mod));
}
if (!k) break;
}
}
for (auto it:mp) if (it.fir.fir==lim-1) {
top=0;
for (int i=1; i<=n; ++i) if (it.fir.sec&(1<<i-1)) sta[++top]=::lim[i];
ans=(ans+it.sec*calc())%mod;
}
printf("%lld\n", (ans%mod+mod)%mod);
}
}
signed main()
{
// freopen("draw.in", "r", stdin);
// freopen("draw.out", "w", stdout);
n=read(); m=read(); c=read();
for (int i=1; i<=n; ++i) lim[i]=read(), id[i]=i;
sort(id+1, id+n+1, [](int a, int b){return lim[a]<lim[b];});
for (int i=1; i<=n; ++i) rk[id[i]]=i;
sort(lim+1, lim+n+1);
for (int i=1,u,v; i<=m; ++i) {
u=rk[read()]; v=rk[read()];
to[u].pb(v); to[v].pb(u);
e[i]={u, v};
}
// if (!m) task1::solve();
// else force::solve();
// task2::solve();
task::solve();
return 0;
}