Educational Codeforces Round 107 (Rated for Div. 2)


Educational Codeforces Round 107 (Rated for Div. 2)

傳送門

E. Colorings and Dominoes

題意:

給一個n * m的矩陣,o表示可以安排為紅格子或藍格子,然后在將一個1 * 2大小的小矩陣放入大矩陣中,橫着放只能放在兩個藍格子里,豎着放只能放在兩個紅格子里。

求所有安排的最大可放小矩陣數的和。

題解:

一開始看到這個題,感覺要用最小割求一個方案中的最大小矩陣數,之后想了一下,因為豎着放只能放在紅格子中,橫着只能在藍格子中,所以同一個格子並不會有我到底是豎着放還是橫着放的取法,也就意味的沒有抉擇,且每一行每一列的貢獻都是獨立的。

所以,我們可以把貢獻拆分,每次只算每一列,每一行的貢獻求和即可。

那么一條的貢獻怎么求,可以用狀態機dp,一維存枚舉到哪個位置,一維存上個點是否可以放小矩陣 ,當s[i]=='o'時,我便可以讓他取紅格子或藍格子。其中一種,可以讓第2維加+1,或者上個點可以放小矩陣我直接加貢獻,其貢獻為,2的未遍歷到的所有0的數次方。

#include<iostream>
#include<vector>
using namespace std;
#define ll long long
const ll N=3e5+7;
const ll mod=998244353;
ll n,m,tot;
string s[N],t[N];
ll dp[N][2],cnt[N],pw[N];
vector<ll>ho;
void init(int n,string s){
	ho.clear();
	for(int i=0;i<n;i++){
		dp[i][0]=dp[i][1]=-1;
		if(i==0)cnt[i]=tot;
		else cnt[i]=cnt[i-1];
		if(s[i]=='o'){
			ho.push_back(1);
			cnt[i]--;
		}
		else{
			ho.push_back(0);
		}
	}
}
ll dfs(ll p,ll k){
	if(p==ho.size()){
		return 0;
	}
	if(dp[p][k]!=-1){
		return dp[p][k];
	}
	ll now=ho[p];
	ll sum=0;
	if(now==1){
		sum+=dfs(p+1,0);
		if(k==1){
			sum+=(dfs(p+1,0)+pw[cnt[p]])%mod;
			sum%=mod;
		}
		else{
			sum+=dfs(p+1,1);
			sum%=mod;
		}
	}
	else{
		sum+=dfs(p+1,0);
		sum%=mod;
	}
	return dp[p][k]=sum;
}
ll pow(ll x,ll n,ll mod)
{
    ll res=1;
	while(n>0){
	   if(n%2==1){
	   	 res=res*x;
	   	 res=res%mod;
	   }
	   x=x*x;
	   x=x%mod;
	   n>>=1;
	}
	return res;
}
void solve(){
	for(int i=0;i<N;i++){
		pw[i]=pow(2,i,mod);
	}
}
int main(){
	solve();
	scanf("%lld%lld",&n,&m);
	for(int i=0;i<n;i++){
		cin>>s[i];
	}
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			if(s[j][i]=='o')tot++;
			t[i]+=s[j][i];
		}
	}
	ll res=0;
	for(int i=0;i<n;i++){
		init(m,s[i]);
		res+=dfs(0,0);
		res%=mod;
	}
	for(int i=0;i<m;i++){
		init(n,t[i]);
		res+=dfs(0,0);
		res%=mod;
	}
	printf("%lld\n",res);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM