首页 > 其他分享 >CF1368G Shifting Dominoes 题解

CF1368G Shifting Dominoes 题解

时间:2022-11-08 13:46:27浏览次数:63  
标签:cnt 题解 ll dfs CF1368G 骨牌 Dominoes id size

CF1368G Shifting Dominoes 题解

题目传送门

CF1368G Shifting Dominoes

题目大意

给你一个 \(n \times m\) 的棋盘,上面有 \(\frac{n \times m}{2}\) 个不重叠的骨牌,你可以删除一个骨牌,并将剩下的骨牌移动。每个骨牌最多移动一格,求棋盘最终局面的方案数。

两个局面不同指两个空位的位置不同。

输入

第一行两个整数 \(n,m\)。

接下来 \(n\) 行,每行一个长度为 \(m\) 且由 \(U,D,R,L\) 的字符串。为 \(U,D,R,L\) 分别表示被骨牌的上、下、左、右半部分覆盖。

输出

一行一个整数,表示方案数。

思路

问题转化

首先可以发现,删掉一个骨牌后,移动剩下的骨牌可以看作是在移动空位。并且可以发现必定是朝一个方向移动 2 格。这提示我们可以建图。只需要按照空位的移动连边即可。举个例子:

建边

看起来这样建图有一点问题:题目要求每个骨牌最多移动一格。但是我们画图发现:

转化

其实一个骨牌移动 2 格就等于移除这一个骨牌

所以其实这样建图没有问题。

我们可以大胆猜测这张图没有环。考虑证明:

当图中存在环时,即出现下图情况:

环

此时我们可以将上图抽象为下图:

抽象后的环

可以发现,连续红色格子的个数必定是奇数,否则构不成环。

所以橙色长方形的边长为奇数,即橙色长方形的格子数也是奇数。

同理可以发现,黄色格子个数为偶数。

红色外框格子个数(骨牌放置的位置)为偶数。

所以绿色格子数(橙色长方形格子数-黄色格子数-红色外框格子数)是奇数。

显然奇数是不能用骨牌铺满的。与题意矛盾。

所以图中不存在环。

即我们建出的图是一个森林。

删掉一个骨牌后的两个点显然不在一个子树,所以问题转化为:给定一个森林,求从不同的树中选两个点的方案数。

记树上节点 \(x\) 的子树大小为 \(siz_x\),则对于每个骨牌的两个节点 \(x,y\),对答案的贡献为 \(siz_x \times siz_y\)。

但是这样统计会有重复。

树上方案数去重,考虑运用 dfs 序的神奇性质。

说到 dfs 序,又有乘积,难想到将乘积的形式转化为面积。

记书上节点 \(x\) 的 dfs 序为 \(dfn_x\)。

转化后即下图所示:

转化为矩阵面积

接下来就可以用扫描线求解答案了。

代码实现

#include<bits/stdc++.h>
#define ll int
const ll N=200010;
using namespace std;

ll n,m;
char S[N];
long long ans;
vector<ll>a[N];//注意用 vector 
vector<ll>e[N];
vector<pair<ll,ll>>t[N];
ll tmp,dfn[N],size[N];
ll cnt,vis[N];
ll b[N];

struct LINE{//线 
	ll x;//横坐标 
	ll y1,y2;//纵坐标区间 
	ll p;//标记 
	bool operator<(LINE a){return x<a.x||x==a.x&&p>a.p;}
}d[N];

struct NODE{//线段树 
	ll cnt,len;
}s[N*8];

ll id(ll x,ll y){//计算编号 
	return (x-1)*m+y;
}

void add(ll x,ll y){//加边 
	e[x].push_back(y);
	vis[y]=1;
}

void dfs(ll x){//计算 size 和 dfn 
	size[x]=1;
	dfn[x]=++tmp;
	for(ll y:e[x]){
		dfs(y);
		size[x]+=size[y];
	}
}

void pushup(ll rt,ll l,ll r){
	if(s[rt].cnt>0)s[rt].len=r-l+1;
	else s[rt].len=s[rt<<1].len+s[rt<<1|1].len;
}

void change(ll rt,ll l,ll r,ll x,ll y,ll v){
	if(x>r||y<l)return;
	ll mid=(l+r)>>1;
	if(x<=l&&r<=y){
		s[rt].cnt+=v;
		pushup(rt,l,r);
		return;
	}
	change(rt<<1,l,mid,x,y,v);
	change(rt<<1|1,mid+1,r,x,y,v);
	pushup(rt,l,r);
}

int main(){
	
	//输入和预处理 
	scanf("%d%d",&n,&m);
	for(ll i=0;i<=n+1;i++){
		a[i].resize(m+3);
	}
	for(ll i=1;i<=n;i++){
		scanf("%s",S+1);
		for(int j=1;j<=m;++j){
			if(S[j]=='U')a[i][j]=1;
			if(S[j]=='D')a[i][j]=2;
			if(S[j]=='L')a[i][j]=3;
			if(S[j]=='R')a[i][j]=4;
		}
	}
	//建图 
	for(ll i=1;i<=n;i++){
		for(ll j=1;j<=m;j++){
			if(j+2<=m&&a[i][j+1]==3)add(id(i,j),id(i,j+2));
			if(j-2>=1&&a[i][j-1]==4)add(id(i,j),id(i,j-2));
			if(i+2<=n&&a[i+1][j]==1)add(id(i,j),id(i+2,j));
			if(i-2>=1&&a[i-1][j]==2)add(id(i,j),id(i-2,j));
			if(!b[id(i,j)]){
				b[id(i,j)]=++cnt;
				if(a[i][j]==3)b[id(i,j+1)]=cnt;
				if(a[i][j]==1)b[id(i+1,j)]=cnt;
			}
			t[b[id(i,j)]].push_back(make_pair(i,j));
		}
	}
	//求 dfn 
	for(ll i=1;i<=n;i++){
		for(ll j=1;j<=m;j++){
			if(!vis[id(i,j)]){
				dfs(id(i,j));
			}
		}
	}
	//转化为矩阵 
	for(ll i=1;i<=cnt;i++){
		ll x1=t[i][0].first,y1=t[i][0].second;
		ll x2=t[i][1].first,y2=t[i][1].second;
		ll u=id(x1,y1),v=id(x2,y2);
		ll l1=dfn[u],r1=dfn[u]+size[u]-1;
		ll l2=dfn[v],r2=dfn[v]+size[v]-1;
		if((x1+y1)&1)swap(l1,l2),swap(r1,r2);
		d[i*2-1]={l1,l2,r2,1};
		d[i*2]={r1+1,l2,r2,-1};
	}
	cnt*=2;
	//排序 
	sort(d+1,d+cnt+1);
	//扫描线 
	for(ll i=1;i<=cnt;i++){
		ans+=(i>1&&d[i].x>=d[i-1].x)*(d[i].x-d[i-1].x)*s[1].len;
		change(1,1,n*m,d[i].y1,d[i].y2,d[i].p);
	}
	printf("%lld",ans);
	
	return 0;
}

尾声

如果你发现了问题,你可以直接回复这篇题解

如果你有更好的想法,也可以直接回复!

标签:cnt,题解,ll,dfs,CF1368G,骨牌,Dominoes,id,size
From: https://www.cnblogs.com/zsc985246/p/16869394.html

相关文章

  • odoo备份数据库无法备份问题解决:Command 'pg_dump' not found.
    背景景:ubuntu20.04上用命令安装postgresql后,odoo备份数据库报如下错误安装命令:sudoapt-getinstallpostgresql默认安装:14版本的pg错误代码如下:  问题原因:是pg......
  • CSP-S 星战题解
    更好的体验首先可以观察出一个性质,只要每个点的出度都是1,那么就一定会满足“每个点都能进入一个环”的性质,也就是说只要每个点出度为1,那么该情况就是合法的。然后考虑怎......
  • AHOI2022山河重整 题解
    首先容易得到\(O(n^2)\)的解法,容易观察得出任意时刻范围都应是\([1,\sum]\)否则直接寄了。考察\(i\)使得\([1,i]\)都能凑出但\(i+1\)不行。则有\(\sum\limits_......
  • Long数据类型序列化Json后传递给前端,产生的精度丢失的问题解决
    问题产生的原因Long类型的数据,如果我们在后端将结果序列化为json,直接传给前端的话,在Long长度大于17位时会出现精度丢失的问题。java中的long能表示的范围比js中number大,......
  • 洛谷--【P1618】三连击升级版题解 排列枚举+循环枚举+stl
    题目描述将 1,2,…,91,2,…,9 共 99 个数分成三组,分别组成三个三位数,且使这三个三位数的比例是 A:B:C,试求出所有满足条件的三个三位数,若无解,输出 No!!!。输入格式......
  • 【题解】CSP-J2022
    CSP-J2022题解/Limie T1.乘方 简要题意:给定a,b,求a^b(a^b表示a的b次方)是否大于10^9,大于输出-1,小于等于输出a^b。分析:此题直接枚举1~b会超时,故考虑用位数判断大小,a^b......
  • BUUCTF [ACTF新生赛2020]SoulLike题解(非爆破)
    查壳发现无壳。   IDA检查main函数显然先检查了输入是否以actf{开头进入sub_83A无法进入 点不进去是因为IDA限制了解析函数的长度,可以修改IDA下cfg......
  • git 问题解决
    1.fatal:theremoteendhungupunexpectedlygitconfig--globalhttp.postBuffer104857600其他方案:gitconfig--globalpack.windowMemory100mgitconfig-......
  • 【题解】codeforces 1746B Rebellion
    题意:给定一个只包含0和1的数组a,可以对a进行以下操作:选定两个下标不同的元素ai和aj,将ai加到aj上,再从数组中删除ai。问最少操作多少次,可以让数组a变成单调非下降子序列(即ai......
  • CSP-S2022题解(T4待填)
    闲话\(\huge{寄}\)\(\text{T1}\)极限脑抽,删掉暴搜打错解,\(70pts\to0pts\);\(\text{T2}\)洛谷\(100pts\)但\(\infin\)\(40pts\),很慌;\(\text{T3}\)差点想到正......