zoukankan      html  css  js  c++  java
  • #轮廓线dp#洛谷 2435 染色

    题目

    有一个 (n)(m) 列的格点图,你需要给每个点上染上 (k) 种颜色中的一种,

    要求没有两个相邻点颜色相同。给定第一行与最后一行的染色,试求总染色方案数。


    分析

    首先对于 (k=2) 要特判,因为存在 (m) 特别大的情况,

    否则可以将每种颜色压成二位二进制,直接状压会TLE,

    (dp[n][m][S]) 表示处理到 ((n,m)) 轮廓线颜色状态为 (S)的方案数,

    还是分第一个格子和其它格子判断,注意 (k=3) 时颜色 3 不能选择。


    代码

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #define rr register
    using namespace std;
    const int N=65536,mod=376544743; bool bbc[N<<1];
    int n,m,k,two[16],f[N],dp[N],al,S;
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    signed main(){
    	n=iut(),m=iut(),k=iut();
    	if (k==2){
    		for (rr int i=0;i<m;++i) bbc[i]=iut();
    		for (rr int i=0;i<m;++i)
    		    if (bbc[i]^iut()^(n&1)^1) return !putchar(48);
    		return !putchar(49);
        }
        two[0]=1;
        for (rr int i=1;i<2*m;++i)
    	    two[i]=two[i-1]<<1;
        for (rr int i=0;i<m;++i){
        	rr int x=iut();
        	if (x&1) S|=two[i<<1];
        	if (x&2) S|=two[i<<1|1]; 
    	}
        dp[S]=1,al=1<<(m*2);
        for (rr int i=1;i<n;++i){
        	memset(f,0,sizeof(int)*al);
        	for (rr int j=0;j<al;++j){
        		if ((j&3)==3&&k==3) continue;
        		for (rr int t=0;t<k;++t)
        		if ((j&3)!=t)
        		    f[j]=mo(f[j],dp[j^(j&3)^t]);
    		}
        	memcpy(dp,f,sizeof(int)*al);
        	for (rr int o=1;o<m;++o){
        		memset(f,0,sizeof(int)*al);
        		for (rr int j=0;j<al;++j){
        			rr int F=j&(two[o*2-2]|two[o*2-1]);
        			rr int now=j&(two[o<<1]|two[o<<1|1]);
        			if (now==F*4) continue;
        			if (now==(two[o<<1]|two[o<<1|1])&&k==3) continue;
        			for (rr int t=0;t<k;++t)
        			if (now!=t*two[o<<1])
        			    f[j]=mo(f[j],dp[j^now^(t*two[o<<1])]);
    			}
        		memcpy(dp,f,sizeof(int)*al);
    		}
    	}
    	S=0;
        for (rr int i=0;i<m;++i){
        	rr int x=iut();
        	if (x&1) S|=two[i<<1];
        	if (x&2) S|=two[i<<1|1]; 
    	}
    	return !printf("%d",dp[S]);
    }
    
  • 相关阅读:
    [基础规范]JavaBeans规范
    leetcode 114.Flatten Binary Tree to Linked List (将二叉树转换链表) 解题思路和方法
    sql 分组取每组的前n条或每组的n%(百分之n)的数据
    D3js-API介绍【中】
    微信公众平台开发 一 账号类别与申请
    Apple Swift编程语言新手教程
    iOS中xib与storyboard原理,与Android界面布局的异同
    Scala入门到精通——第十五节 Case Class与模式匹配(二)
    使用IDA破解TraceMe.exe
    21行python代码实现拼写检查器
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/15183419.html
Copyright © 2011-2022 走看看