题解 回忆
- 当出现形如 \(n\times m\leqslant 100\) 的条件时,若钦定 \(n\leqslant m\) 可以将 \(n\) 约束到根号级别
完全就是考察选手敢不敢写
觉得状态数炸天的就没有分了
觉得可以写写试试就可以 A 了
令 \(f_{i, s, j, k}\) 为到 \(i\) 列,三进制状压连通性为 \(s\),每个连通块 \(siz\) 压为 \(j\),最大连通块 \(siz\) 为 \(k\) 的概率
猜测状态数不多大力转移就可以了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#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 int read() {
int 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 a[45][45];
const ll mod=998244353;
int dlt[][2]={{-1,0},{1,0},{0,1},{0,-1}};
int id[45][45], dsu[45], siz[45], tot;
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void uni(int s, int t) {
s=find(s); t=find(t);
if (s==t) return ;
dsu[s]=t; siz[t]+=siz[s];
}
namespace force{
bool vis[45];
ll ans, val[45];
void solve() {
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) a[i][j]=read();
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) val[id[i][j]=++tot]=a[i][j];
int lim=1<<tot;
for (int s=0; s<lim; ++s) {
int sum=0; ll pre=1;
for (int i=1; i<=tot; ++i)
if (s&(1<<(i-1))) pre=pre*val[i]%mod, vis[i]=1;
else pre=pre*(1-val[i])%mod, vis[i]=0;
for (int i=1; i<=tot; ++i) dsu[i]=i, siz[i]=1;
for (int i=1; i<=n; ++i) {
for (int j=1; j<=m; ++j) if (vis[id[i][j]]) {
for (int k=0; k<4; ++k) {
int x=i+dlt[k][0], y=j+dlt[k][1];
if (vis[id[x][y]]) uni(id[i][j], id[x][y]);
}
}
}
for (int i=1; i<=tot; ++i) if (vis[i]) sum=max(sum, siz[find(i)]);
ans=(ans+sum*pre)%mod;
}
cout<<(ans%mod+mod)%mod<<endl;
}
}
namespace task1{
int ans;
bool vis[45];
void solve() {
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) a[i][j]=read();
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) vis[id[i][j]=++tot]=a[i][j];
for (int i=1; i<=tot; ++i) dsu[i]=i, siz[i]=1;
for (int i=1; i<=n; ++i) {
for (int j=1; j<=m; ++j) if (a[i][j]==1) {
for (int k=0; k<4; ++k) {
int x=i+dlt[k][0], y=j+dlt[k][1];
if (a[x][y]==1) uni(id[i][j], id[x][y]);
}
}
}
for (int i=1; i<=tot; ++i) if (vis[i]) ans=max(ans, siz[find(i)]);
cout<<ans<<endl;
}
}
namespace task3{
ll f[45][45][45], ans;
void solve() {
f[0][0][0]=1;
for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) a[i][j]=read();
for (int i=0; i<m; ++i) {
for (int j=0; j<=i; ++j) {
for (int k=j; k<=i; ++k) {
f[i+1][j+1][max(j+1, k)]=(f[i+1][j+1][max(j+1, k)]+a[1][i+1]*f[i][j][k])%mod;
f[i+1][0][k]=(f[i+1][0][k]+(1-a[1][i+1])*f[i][j][k])%mod;
}
}
}
for (int k=0; k<=m; ++k) {
ll sum=0;
for (int j=0; j<=k; ++j) sum=(sum+f[m][j][k])%mod;
ans=(ans+k*sum)%mod;
}
cout<<(ans%mod+mod)%mod<<endl;
}
}
namespace task4{
ll f[25][4][45][45], ans;
inline void md(ll& a, ll b) {a+=b; a%=mod;}
void solve() {
f[0][0][0][0]=1;
for (int i=0; i<n; ++i) for (int j=1; j<=m; ++j) a[i][j]=read();
for (int i=0; i<=m; ++i) {
for (int s=0; s<4; ++s) {
for (int t=0; t<4; ++t) {
ll pre=1;
for (int j=0; j<2; ++j)
if (t&(1<<j)) pre=pre*a[j][i+1]%mod;
else pre=pre*(1-a[j][i+1])%mod;
for (int j=0; j<=i*2; ++j) {
for (int k=j; k<=i*2; ++k) if (f[i][s][j][k]) {
if (s&t) {
md(f[i+1][t][j+__builtin_popcount(t)][max(j+__builtin_popcount(t), k)], pre*f[i][s][j][k]);
}
else {
md(f[i+1][t][__builtin_popcount(t)][max(__builtin_popcount(t), k)], pre*f[i][s][j][k]);
}
}
}
}
}
}
for (int k=0; k<=m*2; ++k) {
ll sum=0;
for (int t=0; t<4; ++t)
for (int j=0; j<=k; ++j)
sum=(sum+f[m][t][j][k])%mod;
ans=(ans+k*sum)%mod;
}
cout<<(ans%mod+mod)%mod<<endl;
}
}
namespace task2{
ll ans;
bool vis[10], linked[4], ided[20];
short s[45], siz[45], dsu[20], usiz[20], bel[20], id[20], isiz[20];
inline short find(short p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
inline void md(ll& a, ll b) {a+=b; a%=mod;}
inline void uni(int s, int t) {
s=find(s); t=find(t);
if (s==t) return ;
dsu[s]=t; usiz[t]+=usiz[s];
}
struct st{
short i, s, k; int j;
st():i(0),s(0),j(0),k(0){}
st(short a, short b, int c, short d):i(a),s(b),j(c),k(d){}
inline ll qval();
};
map<st, ll> mp;
inline ll st::qval() {return mp[*this];}
inline bool operator < (st a, st b) {
if (a.i!=b.i) return a.i<b.i;
if (a.s!=b.s) return a.s<b.s;
if (a.j!=b.j) return a.j<b.j;
if (a.k!=b.k) return a.k<b.k;
return 0;
}
queue<st> q;
inline void decode(st u) {
for (int i=0; i<n; ++i) s[i]=u.s%4, u.s/=4;
for (int i=1; i<=3; ++i) siz[i]=u.j&((1<<8)-1), u.j>>=8;
}
inline st encode(short i, short* s, short* siz, short k) {
st ans(i, 0, 0, k);
for (int i=n-1; ~i; --i) ans.s=ans.s*4+s[i];
for (int i=3; i; --i) ans.j=(ans.j<<8)|siz[i];
return ans;
}
void solve() {
// cout<<double(sizeof(f))/1000/1000<<endl;
for (int i=0; i<n; ++i) for (int j=1; j<=m; ++j) a[i][j]=read();
if (n>m) {
for (int i=0; i<n; ++i)
for (int j=1; j<=i; ++j)
swap(a[i][j], a[j-1][i+1]);
swap(n, m);
}
// for (int i=0; i<n; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]<<' '; cout<<endl;}
q.push(st(0, 0, 0, 0));
mp[st(0, 0, 0, 0)]=1;
int lim=1<<n;
while (q.size()) {
st u=q.front(); q.pop();
if (u.i==m) {ans=(ans+mp[u]*u.k)%mod; continue;}
decode(u);
if (!mp[u]) continue;
// cout<<"u: "<<u.i<<' '<<u.k<<endl;
// cout<<"s: "; for (int i=0; i<n; ++i) cout<<s[i]<<' '; cout<<endl;
// cout<<"siz: "; for (int i=1; i<=3; ++i) cout<<siz[i]<<' '; cout<<endl;
// cout<<"val: "<<mp[u]<<endl;
// cout<<endl;
for (int t=0; t<lim; ++t) {
ll pre=1; int tot=0; short msiz=0;
for (int i=0; i<n; ++i)
if (t&(1<<i)) pre=pre*a[i][u.i+1]%mod, vis[i]=1;
else pre=pre*(1-a[i][u.i+1])%mod, vis[i]=0;
// memset(linked, 0, sizeof(linked)); linked[0]=1;
memset(id, 0, sizeof(id));
memset(isiz, 0, sizeof(isiz));
for (int i=0; i<n; ++i) dsu[i]=i, usiz[i]=1;
for (int i=n; i<=2*n; ++i) dsu[i]=i, usiz[i]=0;
for (int i=0; i<n; ++i) if (vis[i]&&vis[i+1]) uni(i, i+1);
for (int i=0; i<n; ++i) if (s[i]) usiz[find(s[i]+n)]=siz[s[i]];
for (int i=0; i<n; ++i) if (s[i] && vis[i]) uni(i, s[i]+n);
for (int i=0; i<n; ++i) bel[i]=find(i);
// cout<<"s: "; for (int i=0; i<n; ++i) cout<<s[i]<<' '; cout<<endl;
// cout<<"vis: "; for (int i=0; i<n; ++i) cout<<vis[i]<<' '; cout<<endl;
// cout<<"dsu: "; for (int i=0; i<=2*n; ++i) cout<<dsu[i]<<' '; cout<<endl;
// cout<<"bel: "; for (int i=0; i<n; ++i) cout<<find(i)<<' '; cout<<endl;
// cout<<"siz: "; for (int i=1; i<=3; ++i) cout<<siz[i]<<' '; cout<<endl;
for (int i=0; i<n; ++i)
if (vis[i]) {
if (!id[bel[i]]) id[bel[i]]=++tot, isiz[tot]=usiz[bel[i]];
msiz=max(msiz, usiz[bel[i]]);
bel[i]=id[bel[i]];
}
else bel[i]=0;
// cout<<"pre: "<<pre<<endl;
// cout<<"tem: "<<u.i+1<<' '<<max(msiz, u.k)<<endl;
// cout<<"s: "; for (int i=0; i<n; ++i) cout<<bel[i]<<' '; cout<<endl;
// cout<<"siz: "; for (int i=1; i<=3; ++i) cout<<isiz[i]<<' '; cout<<endl;
// cout<<endl;
st tem=encode(u.i+1, bel, isiz, max(msiz, u.k));
if (mp.find(tem)==mp.end()) q.push(tem);
md(mp[tem], pre*mp[u]);
}
}
cout<<(ans%mod+mod)%mod<<endl;
}
}
signed main()
{
freopen("memory.in", "r", stdin);
freopen("memory.out", "w", stdout);
n=read(); m=read();
// force::solve();
task2::solve();
// if (n==1) task3::solve();
// else if (n*m<=26) force::solve();
// else if (n==2) task4::solve();
// else task1::solve();
return 0;
}