• 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
    ",res);
    }
    
  • 相关阅读:
    SQL将表中某一类型的一列拼接成一行
    javascript中把一个数组的内容全部赋值给另外一个数组
    Socket接口原理及用C#语言实现
    Linq表连接大全(INNER JOIN、LEFT OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOIN、CROSS JOIN)
    C#中对DataTable进行全连接后group by,orderby
    循环删除DataTable.Row中的多行问题
    跨库连接报错Server 'myLinkedServer' is not configured for RPC
    执行远程存储过程并插入到临时表中
    无法定位程序输入点_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4findEPKcj于动态链接库上
    Qt 日期时间
  • 原文地址:https://www.cnblogs.com/whitelily/p/14651879.html
Copyright © 2020-2023  润新知