0228模拟赛(兔)

文明种植计划

题意

\(~~~~\) 一个排列初始时 \(p_i=i\),给出 \(n\) 个数的目标位置(\(n\) 为偶数),每次允许交换满足 \(2|i-j|\geq n\) 的两个位置 \(i,j\) 上的数。构造一组在 \(M\leq 3\times 10^5\) 以内的方案。
\(~~~~\) \(1\leq n\leq 3\times 10^5\).

题解

\(~~~~\) 原题 CF1148C 限制是 \(5n\),随便搞。

\(~~~~\) 这题我们考虑一种在三步之内交换两个东西的方法,具体来说如果我们想把 \(y\) 换到 \(x\)

\(~~~~\) 如果两个能直接互换那直接换即可,否则:

\(~~~~\)\(x,y\) 同在某一侧,那就利用另一侧的端点来换。若在异侧,那么把 \(y\) 先换到对侧的端点,交换 \(1\)\(n\) 再换到 \(x\) 即可。

\(~~~~\) 可以发现把每个数换到一个位置用 \(3\) 步及以内,那就直接把每个数换到目标位置即可。当然因为 \(1\)\(n\) 在过程中会被打乱,所以 \(1\)\(n\) 要最后来放。

代码
查看代码
// LUOGU_RID: 103248552
#include <bits/stdc++.h>
#define ll long long
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T f=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=f;
}
vector<PII>Ans;
int n,Aim[300005],P[300005],pos[300005],To[300005];
inline int Abs(int x){return x>=0?x:-x;}
void Swap(int x,int y)
{
	if(2*Abs(x-y)>=n) Ans.push_back(mp(x,y)),swap(P[x],P[y]),pos[P[x]]=x,pos[P[y]]=y;
	else
	{
		if(x<=n/2&&y<=n/2)
		{
			Ans.push_back(mp(x,n));
			Ans.push_back(mp(n,y));
			Ans.push_back(mp(x,n));
			swap(P[x],P[y]); pos[P[x]]=x; pos[P[y]]=y;
		}
		else if(x>n/2&&y>n/2)
		{
			Ans.push_back(mp(x,1));
			Ans.push_back(mp(1,y));
			Ans.push_back(mp(x,1));
			swap(P[x],P[y]); pos[P[x]]=x; pos[P[y]]=y;
		}
		else if(x<=n/2&&y>n/2)
		{
			Ans.push_back(mp(y,1));
			Ans.push_back(mp(1,n));
			Ans.push_back(mp(n,x));
			swap(P[y],P[1]);swap(P[1],P[n]);swap(P[n],P[x]);
			pos[P[x]]=x; pos[P[n]]=n; pos[P[1]]=1; pos[P[y]]=y; 
		}
		else
		{
			Ans.push_back(mp(x,n));
			Ans.push_back(mp(1,n));
			Ans.push_back(mp(n,y));
			swap(P[x],P[n]); swap(P[1],P[n]); swap(P[n],P[y]);
			pos[P[x]]=x; pos[P[n]]=n; pos[P[1]]=1; pos[P[y]]=y; 
		}
	}
	
}
int main() {
//	freopen("project.in","r",stdin);
//	freopen("project.out","w",stdout);
	read(n);
	for(int i=1,x;i<=n;i++) read(x),Aim[x]=i,To[i]=x;
	for(int i=1;i<=n;i++) P[i]=i,pos[i]=i;
	for(int i=2;i<n;i++)
	{
		if(Aim[i]!=P[i])
			Swap(i,pos[Aim[i]]);
	}
	if(Aim[1]!=P[1]) Swap(pos[Aim[1]],1);
	if(Aim[n]!=P[n]) Swap(pos[Aim[n]],n);
	printf("%d\n",(int)Ans.size());
	for(int i=0;i<(int)Ans.size();i++) printf("%d %d\n",Ans[i].first,Ans[i].second);
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。
*/ 

创世神的引导

\(~~~~\) 是一道捐出去的原创题,所以应出题人要求不写。


闯入的观测者

题意

\(~~~~\)\(n\) 行的三角形,第 \(i\) 行有 \(i\) 个数。从 \((1,1)\) 开始画折线,每次 \((i,j)\)\((i+1,j)\)\((i+1,j+1)\) 画折线,要求共 \(m\) 条折线,每条折线都不在上一条折线的左侧。且有 \(k\) 个限制 \((x,y,z)\),表示第 \(x\) 条折线在 \((y,c)\) 画折线必须向 \((y+1,c+z)\)
\(~~~~\) \(1\leq n,m\leq 20\).

题解

\(~~~~\) 考虑 \(dp_{i,S}\) 表示第 \(i\) 条折线,状态为 \(S\),那么直接转移复杂度 \(\mathcal{O(4^n \text{Poly}(n))}\),显然过不了。

\(~~~~\) 我们一格一格来,这样是 \(\mathcal{O(nm)}\) 的状态阶段,但是可以 \(\mathcal{O(1)}\) 转移过来。(类似轮廓线dp)但是怎么判左侧这个限制呢?还得加一维来记录上一条线在这里的 \(j\)。这样是 \(\mathcal{O(2^nn^2m)}\) 的,看起来很接近了,再优化一点点。

\(~~~~\) 我们发现实质是上一条线的 \(\operatorname{popcount}\) 前缀和时刻小于等于这条线的 \(\operatorname{popcount}\) 前缀和,那我们就不记录上一条线在这里的位置,而是改为如果在某个位置走了 \(1\) 那就把剩下的限制放宽即可,也即减去 \(\operatorname{lowbit}\).

代码
查看代码
#include <bits/stdc++.h>
#define PII pair<int,int>
#define mp(a,b) make_pair(a,b)
using namespace std;
template<typename T>void read(T &x)
{
    T sig=1;x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')sig=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    x*=sig;
}
const int MOD=1e9+7;
inline int Add(int a,int b){return (a+b)%MOD;}
inline int Dec(int a,int b){return (a-b+MOD)%MOD;}
inline int Mul(int a,int b){return 1ll*a*b%MOD;}
int f[25][25],dp[25][1048580];
inline int lowbit(int x){return x&(-x);}
int main() {
	memset(f,-1,sizeof(f));
	int n,m,q;
	read(n);read(m);read(q);
	for(int i=1,x,y,z;i<=q;i++) read(x),read(y),read(z),f[x][y]=z;
	dp[0][0]=1;int Now=0;
	for(int i=1;i<=m;i++)
	{
		for(int qwq=1,Tmp=1,now=(1<<(n-1))-1;qwq<n;qwq++,now-=Tmp,Tmp<<=1)
		{
			if(f[i][qwq]==0)
			{
				Now++; memset(dp[Now&1],0,sizeof(dp[Now&1]));
				for(int k=0;k<(1<<(n-1));k++)
					if(!(k&Tmp)) dp[Now&1][k]=Add(dp[Now&1][k],dp[!(Now&1)][k]);
			}
			if(f[i][qwq]==1)
			{
				Now++; memset(dp[Now&1],0,sizeof(dp[Now&1]));
				for(int k=0;k<(1<<(n-1));k++)
					dp[Now&1][k-lowbit(k&now)+Tmp]=Add(dp[Now&1][k-lowbit(k&now)+Tmp],dp[!(Now&1)][k]); 
			}
			if(f[i][qwq]==-1)
			{
				Now++; memset(dp[Now&1],0,sizeof(dp[Now&1]));	
				for(int k=0;k<(1<<(n-1));k++)
				{
					if(!(k&Tmp)) dp[Now&1][k]=Add(dp[Now&1][k],dp[!(Now&1)][k]);
					dp[Now&1][k-lowbit(k&now)+Tmp]=Add(dp[Now&1][k-lowbit(k&now)+Tmp],dp[!(Now&1)][k]);
				}
			}
		}
	}
	int Ans=0;
	for(int i=0;i<(1<<(n-1));i++) Ans=Add(Ans,dp[Now&1][i]);
	printf("%d",Ans);
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。
*/

岁月史书

【假题已删除】

posted @ 2023-02-28 17:36  Azazеl  阅读(29)  评论(0编辑  收藏  举报