[提高组互测] Day6

总结

这签到构造题我做不出也没有办法啊\(...\)

还是感谢 \(\tt Oneindark\) 大佬的供题,希望她以后不要再出阴间构造题啦!

Ciel and Flipboard

题目描述

点此看题

解法

我是这样打爆搜的,枚举左上角 \(m\times m\) 个元素的状态,那么整个矩阵的状态是唯一确定的。因为操作矩阵个数也是 \(m\times m\) 个,我们可以知道它们是线性不相关的。

下一个结论就比较难观察出来了,因为长度是 \(m=\frac{n+1}{2}\) 很特殊,设 \(s(x,y)\) 表示位置 \((x,y)\) 的符号位,如果是 \(1\) 我们设置成 \(0\),如果是 \(-1\) 我们设置成 \(1\),可以发现:

\[s(x,y)\oplus s(x,y+m)\oplus s(x,m)=0 \]

\[s(x,y)\oplus s(x+m,y)\oplus s(m,y)=0 \]

对这两个式子更深的理解就是当我们确定了"中线"以后,两边的符号位就是对应的。

\(\tt Rainybunny\) 通过打表发现了这个结论,这种符号位问题通常存在特殊结论哦~~

那么我们枚举 \(s(m,i),i\leq m\),这时候 \(m\) 这一整行都能够确定,然后发现每一行是互相独立的,对于每一行单独做,我们先枚举中间点,然后枚举左上角的点,这时候四个点都确定了:

那么疯狂取最大值就行了,时间复杂度 \(O(2^mm^2)\)

总结

想办法把变量独立起来,然后分别去最值,你可能需要枚举一些关键变量。

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 50;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,ans,a[M][M];
int val(int x,int y)
{
	return x==0?y:-y;
}
int check(int S)
{
	int o=S>>m-1,res=0;
	for(int i=1;i<=m;i++)
		res+=val((S>>i-1)&1,a[m][i]);
	for(int i=m+1;i<=n;i++)
		res+=val(o^((S>>i-m-1)&1),a[m][i]);
	for(int i=1;i<m;i++)
	{
		int mx=-(1ll<<60);
		for(int p=0;p<2;p++)
		{
			int s=val(p,a[i][m])+val(o^p,a[i+m][m]);
			for(int j=1;j<m;j++)
			{
				int x=a[i][j]+val(p,a[i][m+j])
				+val((S>>j-1)&1,a[m+i][j])
				+val(((S>>j-1)&1)^o^p,a[i+m][j+m]);
				if(x<0) x=-x;s+=x;
			}
			mx=max(mx,s);
		}
		res+=mx;
	}
	return res;
}
signed main()
{
	//freopen("taozi.in","r",stdin);
	//freopen("taozi.out","w",stdout);
	n=read();m=(n+1)/2;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			a[i][j]=read();
	for(int i=0;i<(1<<m);i++)
		ans=max(ans,check(i));
	printf("%lld\n",ans);
}

Shifting Dominoes

题目描述

点此看题

解法

考虑两个空格的独立性,首先我们可以把矩阵黑白染色,那么空格初始颜色就不同,并且每次都是把平移两格,所以颜色是不会变的,这提示黑色格和白色格可以分开处理。

那么对于一个空格我们想求出它能到达的点,可以用图论表示这个过程,具体来说我们这样连边:

这个边就代表了空格能够沿着边的方向转移,不难发现每个点的入度至多为 \(1\),所以这是可以基环外向树,你可以通过反证如果构成环内部点数为奇数来说明不会有环,所以我们得到了一个树形结构

那么一个空格能到达的位置对应着树上的一个子树,我们可以把它表示成一个 \(\tt dfn\) 序区间,综合考虑两维就变成了一个矩形求并问题,用扫描线解决即可,时间复杂度 \(O(nm\log nm)\)

总结

多个对象的问题可以找独立性来转化成单个对象的问题。

遇到奇怪的问题可以多想想图论,基本的分析还是要有。

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 200005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,k,t,Ind,p[M][2],cl[M],rt[M],di[M],dt[M];
vector<int> g[M];char s[M];long long ans;
struct node
{
	int x,l,r,f;
	bool operator < (const node &b) const
	{
		return x<b.x;
	}
}q[M];
int id(int x,int y)
{
	return (x-1)*m+y;
}
void add(int x,int y,int a,int b)
{
	g[id(x,y)].push_back(id(a,b));
	rt[id(a,b)]=1;
}
void dfs(int u)
{
	di[u]=++Ind;
	for(auto v:g[u])
		if(!di[v]) dfs(v);
	dt[u]=Ind;
}
int mi[4*M],num[4*M],tag[4*M];
void upd(int i,int c)
{
	tag[i]+=c;
	mi[i]+=c;
}
void down(int i)
{
	if(!tag[i]) return ;
	upd(i<<1,tag[i]);
	upd(i<<1|1,tag[i]);
	tag[i]=0;
}
void build(int i,int l,int r)
{
	num[i]=r-l+1;mi[i]=0;
	if(l==r) return ;
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
}
void add(int i,int l,int r,int L,int R,int f)
{
	if(L>r || l>R) return ;
	if(L<=l && r<=R)
	{
		upd(i,f);
		return ;
	}
	int mid=(l+r)>>1;down(i);
	add(i<<1,l,mid,L,R,f);
	add(i<<1|1,mid+1,r,L,R,f);
	mi[i]=min(mi[i<<1],mi[i<<1|1]);num[i]=0;
	if(mi[i]==mi[i<<1]) num[i]=num[i<<1];
	if(mi[i]==mi[i<<1|1]) num[i]+=num[i<<1|1];
}
int main()
{
	//freopen("domino.in","r",stdin);
	//freopen("domino.out","w",stdout);
	n=read();m=read();
	//build the graph
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for(int j=1;j<=m;j++)
		{
			cl[id(i,j)]=(i+j)&1;
			if(s[j]=='L' && j+2<=m)
				add(i,j+2,i,j);
			if(s[j]=='R' && j-2>=1)
				add(i,j-2,i,j);
			if(s[j]=='U' && i+2<=n)
				add(i+2,j,i,j);
			if(s[j]=='D' && i-2>=1)
				add(i-2,j,i,j);
			if(s[j]=='L' || s[j]=='U')
			{
				++k;p[k][0]=id(i,j);
				if(s[j]=='L') p[k][1]=id(i,j+1);
				if(s[j]=='U') p[k][1]=id(i+1,j);
			}
		}
	}
	for(int i=1;i<=n*m;i++)
		if(!rt[i]) dfs(i);
	for(int i=1;i<=k;i++)
	{
		int x=p[i][0],y=p[i][1];
		if(cl[x]) swap(x,y);
		q[++t]=node{di[x],di[y],dt[y],1};
		q[++t]=node{dt[x]+1,di[y],dt[y],-1};
	}
	//scaning line
	sort(q+1,q+1+t);k=n*m;
	build(1,1,k);
	for(int i=1,j=1;i<=k;i++)
	{
		while(j<=t && q[j].x<=i)
		{
			add(1,1,k,q[j].l,q[j].r,q[j].f);
			j++;
		}
		ans+=k-(mi[1]==0?num[1]:0);
	}
	printf("%lld\n",ans);
}
posted @ 2021-10-19 10:27  C202044zxy  阅读(216)  评论(0编辑  收藏  举报