• 【题解】多边形染色


    Link

    蒟蒻做的为数不多的环形(dp),技巧不到位,写题解来总结一下。

    ( ext{Solution:})

    (dp)柿子还是很好推出来的:(dp[i][j])表示地(i)个点染色是(j)的方案数。先考虑没有限制的转移:

    [dp[i][j]=sum_{k ot=j} dp[i-1][k] ]

    最后注意一下(1,n)的限制。

    这题多了三个操作,分别是:限制相邻两个颜色一样,限制固定颜色,以及限制不能填的颜色。

    那么我们分类讨论一下,对于有相邻颜色一样的点,就可以从上一步的相同颜色转移而来,同时注意一下是不是有其他两种操作即可。

    对于没有相邻颜色限制的点,考虑其他限制,有固定颜色的枚举上一个所有不同于固定颜色的颜色转移;有不能填的颜色的枚举上一个所有颜色特判一下就行。

    这题的主要难点在于环形后效性的处理。对于我这种没怎么写过环形(dp)的人,还是有点生疏。

    对于这个题,瞪眼法看出最后一个颜色与第一个颜色是有关联的。那么我们可以钦定第一个点的颜色,进行(c)(dp)就可以方便地处理后效性啦。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int mod=987654321;
    int n,m,c,ans;
    int col[50010],dp[50010][11];
    //dp[i]表示i这个点是p颜色,1-i一共的方案数
    int vis[50010],sum[50010];
    int dislike[50010][20];
    signed main() {
    	scanf("%lld%lld%lld",&n,&m,&c);
    	for(int i=1; i<=m; ++i) {
    		int opt,x,y;
    		scanf("%lld%lld%lld",&opt,&x,&y);
    		if(opt==1)for(int i=1;i<=c;++i){if(i!=y)dislike[x][i]=1;}
    		if(opt==2)dislike[x][y]=1;
    		if(opt==3) {
    			if(y>x)swap(x,y);
    			vis[x]=y;
    		}
    	}
    	//vis[big]=small
    	/*if(col[1]==0){
    		for(int i=1;i<=c;++i)dp[1][i]=1;
    	}
    	if(col[1]!=0){
    		if(col[1]>0)dp[1][col[1]]=1;
    		else{
    			for(int i=1;i<=c;++i){
    				if(i==-col[1])continue;
    				dp[1][i]=1;
    			}
    		}
    	}
    	for(int i=1;i<=n;++i){
    		if(!vis[i])continue;
    		if(col[i]<=0)continue;
    		col[vis[i]]=col[i];
    	}
    	for(int i=1;i<=c;++i)sum[1]+=dp[1][i];
    	for(int i=2;i<=n;++i){
    		if(col[i]==0&&!vis[i]){
    			//无限制
    			for(int j=1;j<=c;++j){
    				dp[i][j]*=(sum[i-1]-dp[i-1][j]);
    			}
    		}
    		else if(col[i]==0&&vis[i]){
    
    		}
    	}*/
    	/*if(col[1]==0)for(int i=1;i<=c;++i)dp[1][i]=1;
    	else if(col[1]>0)dp[1][col[1]]=1;
    	else for(int i=1;i<=c;++i){if(i!=-col[1])dp[1][i]=1;}
    	for(int i=2;i<=n;++i){
    		if(vis[i]){
    			if(col[i]==0){
    				for(int j=1;j<=c;++j)dp[i][j]=dp[i-1][j];
    			}
    			else{
    				if(col[i]<0){
    					for(int j=1;j<=c;++j){
    						if(j==-col[i])continue;
    						dp[i][j]=dp[i-1][j];
    					}
    				}
    				else{
    					dp[i][col[i]]=dp[i-1][col[i]];
    				}
    			}
    		}
    		else{
    			//not same&&col is free
    			if(col[i]==0){
    				for(int j=1;j<=c;++j){
    					for(int k=1;k<=c;++k){
    						if(j==k)continue;
    						dp[i][j]+=dp[i-1][k];
    					}
    				}
    				//cout<<"qwq
    ";
    			}
    			else if(col[i]<0){
    				for(int j=1;j<=c;++j){
    					if(j==-col[i])continue;
    					for(int k=1;k<=c;++k){
    						if(j==k)continue;
    						dp[i][j]+=dp[i-1][k];
    					}
    				}
    			}
    			else{
    				for(int j=1;j<=c;++j){
    					if(j==col[i])continue;
    					dp[i][col[i]]+=dp[i-1][j];
    				}
    			}
    		}
    	}*/
    	for(int p=1; p<=c; ++p) {
    		//one's color
    		if(-col[1]==p)continue;
    		for(int i=1; i<=n; ++i)for(int j=1; j<=c; ++j)dp[i][j]=0;//prepare for
    		dp[1][p]=1;//first
    		for(int i=2; i<n; ++i) {
    			
    			for(int j=1; j<=c; ++j) {
    				if(dislike[i][j])continue;
    				if(vis[i]) {
    					dp[i][j]+=dp[i-1][j];
    					dp[i][j]%=mod;
    				} else {
    					for(int k=1; k<=c; ++k) {
    						if(k==j)continue;
    						dp[i][j]+=dp[i-1][k];
    						dp[i][j]%=mod;
    					}
    				}
    			}
    		}
    			for(int i=1; i<=c; ++i) {
    				if(dislike[n][i]||i==p)continue;
    				if(vis[n])dp[n][i]+=dp[n-1][i],dp[n][i]%=mod;
    				else {
    					for(int j=1; j<=c; ++j) {
    						if(i==j)continue;
    						dp[n][i]+=dp[n-1][j];
    						dp[n][i]%=mod;
    					}
    				}
    			}
    		for(int i=1; i<=c; ++i)ans+=dp[n][i],ans%=mod;
    	}
    	printf("%lld
    ",ans%mod);
    	return 0;
    }
    

    注意题目细节,操作(1,2)并不一定只有一个,所以要开一个数组来存储所有不能染的颜色,就是代码中的(dislike[][].)

    看代码中思路不清晰的后果,注释了一大堆,写了一百五十多行……

  • 相关阅读:
    AtCoder Grand Contest 001
    在AT151上面测试串口通讯
    i2c tools 使用
    STM32CUBEF4 实现USB 虚拟串口
    SPI总线工作模式
    树莓派3b+ wifi无线连接
    树莓派开机运行Python脚本 控制LED灯闪烁
    树莓派 使用python来操作GPIO 控制LED灯
    解决树莓派新版系统 ssh连接不了问题
    C# textBox控件只允许为数字和小数点并且提取出这个数字
  • 原文地址:https://www.cnblogs.com/h-lka/p/12821358.html
Copyright © 2020-2023  润新知