[Luogu P3160] [CQOI2012] local minimum

preface

[Title portal]
What a difficult question

Mental journey:

  • I have no idea.
  • Crazy problem solving.
  • The code is too long and wants to give up.
  • After sorting out the ideas, I found that the core is not so complex.
  • Start writing according to a piece of code.
  • Transfer to 90pts\ after finishing writing.
  • Finally.

There are so many implementation details that I don't notice at all.
Time spent: \ (3h \).

Problem solution

Basic ideas of DP

To tell you the truth, it's embarrassing that I didn't even design a simple DP, or I don't know how to transfer it
When you see the data range, you can probably think of the shape pressure DP.
Here's the problem. What's the pressure?
Think about it carefully. What is related to the topic and can be pressed is the smallest point (only \ (8 \) at most).
Therefore, one dimension represents the selection state of the minimum point.
So in order to transfer, naturally add a one-dimensional representation, select a few numbers, just in line with the space, good.
Next, determine the transfer order
If you fill in numbers from small to large, the adjacent points must not be filled in before filling in a minimum point.
Therefore, you can know which points can be selected in each state (in fact, you need to know how many points can be selected).
Transfer can be divided into two cases: put at the minimum point / not at the minimum point.

Further thinking + tolerance and exclusion

But what is the answer?
In fact, we guarantee that the position of each X must be a local minimum, but we do not guarantee that the position of each X must not be a local minimum.
So subtract the case of misplacing a high point.
However, this will reduce more. For example, if two high points are misplaced at the same time, it will be reduced again.
This is a problem of tolerance and exclusion.

In fact, I haven't systematically learned about inclusion and exclusion. My understanding is that subtracting part will subtract more overlapping parts. According to mathematical induction, each layer is in the form of "adding one layer, subtracting one layer", which can be deduced to the bottom layer. (actually, there is a formula)
(PS: simple inclusion and exclusion can also be realized by bit operation, but it has nothing to do with this problem)

You can use DFS to enumerate every. That can be changed to X, rerun DP to calculate the answer, and increase or decrease according to the tolerance and exclusion. (this DFS is also disgusting)

A little detail

If you don't meet the conditions at the beginning, you can directly make a special judgment.

Code (nanny level comments)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 1<<8,mod = 12345678;
char s[5][8];
int n,m,px[31],py[31];
ll dp[N][31],ans;
bool vis[6][9];
int dx[9] = {0,1,0,-1,0,1,1,-1,-1};
int dy[9] = {0,0,1,0,-1,1,-1,1,-1};
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
void print_map()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) printf("%c",s[i][j]);
		printf("\n");
	}
}
int calc()//Calculate the number of schemes according to the current status 
{
	int cnt=0; 
	for(int i=1;i<=n;i++)	
		for(int j=1;j<=m;j++)	
			if(s[i][j]=='X') px[++cnt]=i,py[cnt]=j;
	//print_map();
	memset(dp,0,sizeof(dp));
	dp[0][0]=1;
	for(int mask=0;mask<(1<<cnt);mask++)//Enumeration status 
	{
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=cnt;i++)//Mark which points cannot be selected in the current state
			if(!(mask&(1<<(i-1))))//The points around each minimum point cannot be selected 
				for(int j=0;j<=8;j++)
					vis[px[i]+dx[j]][py[i]+dy[j]]=1;
		int tot=0;
		for(int i=1;i<=n;i++)	 
			for(int j=1;j<=m;j++) tot+=!vis[i][j];//Calculate how many points can be selected 
		//printf("tot=%d\n",tot);
		for(int i=0;i<=tot;i++)	//Brush table method, i starting from 0 
			if(dp[mask][i])
			{
				(dp[mask][i+1]+=dp[mask][i]*(tot-i))%=mod;//The current number is not placed at the minimum 
				for(int j=0;j<cnt;j++)	
					if(!(mask&(1<<j))) 
						(dp[mask|(1<<j)][i+1]+=dp[mask][i])%=mod;//Put the current number at the minimum 
			}
	}
	//printf("dp:%d\n",dp[(1<<cnt)-1][n*m]); 
	return dp[(1<<cnt)-1][n*m];
}
void dfs(int x,int y,int op)//op is an inclusive sign 
{//dfs fills in new states one by one from top left to bottom right 
	if(x==n+1) {ans=(ans+op*calc()%mod+mod)%mod;return;}
	if(y==m+1) {dfs(x+1,1,op);return;}
	dfs(x,y+1,op);//Do not change the type of the current point 
	bool flag=1;
	for(int i=0;i<=8;i++)
	{//Judge whether the current point type can be changed 
		int tx=x+dx[i],ty=y+dy[i];
		if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&s[tx][ty]=='X') flag=0;
	}	
	if(flag) 
	{
		s[x][y]='X';
		dfs(x,y+1,-op);//Change the type of the current point 
		s[x][y]='.';
	}
		
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++)	
		for(int j=1;j<=m;j++)	
			if(s[i][j]=='X')
				for(int k=1;k<=8;k++)
				{
					int x=i+dx[k],y=j+dy[k];
					if(x>=1&&x<=n&&y>=1&&y<=m&&s[x][y]=='X')
						return puts("0"),0;//Illegal initial state of special judgment 
				}
	dfs(1,1,1);
	printf("%lld\n",(ans+mod)%mod);
	return 0;
}

Posted by Wave on Tue, 02 Nov 2021 13:55:59 -0700