题解 回忆

传送门

  • 当出现形如 \(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;
}
posted @ 2022-03-07 18:12  Administrator-09  阅读(1)  评论(0编辑  收藏  举报