首页 > 其他分享 >2023.3.27 日寄

2023.3.27 日寄

时间:2023-03-27 22:33:05浏览次数:35  
标签:ch int 矩阵 2023.3 -- while 27 Ans

2023.03.27

模拟赛

\(~~~~\) 什么叫挂大分啊。

飞鸟和蝉

题意

\(~~~~\) 第 \(i\) 个点有权值,每个点可以跳 \([i-a_i,i+a_i]\) 内所有点。求序列上两个点之间互相到达的最小跳跃次数的最大值。
\(~~~~\) \(1\leq n\leq 2\times 10^5\).

题解

\(~~~~\) 考虑二分答案,即是否存在一对其互相到达次数都大于等于 \(d\)。

\(~~~~\) 这种题很显然的倍增套路,假设我们预处理出来过后那就可以计算出跳 \(d\) 次点 \(i\) 可以到达的区间 \(l_i,r_i\),于是就是求 \(u\in [l_v,r_v],v\in [l_u,r_u]\) 的点对 \((u,v)\) 是否存在。把所有 \(l\) 离线下来从小到大做,BIT 查询是否存在即可。

\(~~~~\) 在普通 ST 表上加一维表示跳 \(2^t\) 后 \(i\) 的左/右区间。

代码
查看代码
#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;
}
int n,L[19][19][300005],R[19][19][300005];
inline int QueryL(int x,int l,int r)
{
	int t=__lg(r-l+1);
	return min(L[x][t][l],L[x][t][r-(1<<t)+1]);
}
inline int QueryR(int x,int l,int r)
{
	int t=__lg(r-l+1);
	return max(R[x][t][l],R[x][t][r-(1<<t)+1]);
}
struct node{
	int l,id;
	node(){}
	node(int LL,int ID){l=LL,id=ID;}
}P[300005];
inline bool cmp(node a,node b){return a.l<b.l;}
struct BIT{
	int tr[300005];
	inline int lowbit(int x){return x&(-x);}
	void Clear(){for(int i=1;i<=n;i++) tr[i]=0;}
	inline void Add(int x,int Val){for(;x<=n;x+=lowbit(x)) tr[x]+=Val;}
	inline int Query(int x){int ret=0;for(;x;x-=lowbit(x)) ret+=tr[x];return ret;}
}BIT;
int posl[300005],posr[300005];
inline bool check(int mid)
{
	BIT.Clear();
	for(int i=1;i<=n;i++)
	{
		posl[i]=posr[i]=i;
		for(int j=18;j>=0;j--)
		{
			if((mid>>j)&1)
			{
				int Tmpl=QueryL(j,posl[i],posr[i]),Tmpr=QueryR(j,posl[i],posr[i]);
				posl[i]=Tmpl; posr[i]=Tmpr;
			}
		}
		P[i]=node(posl[i],i);
	}
	int now=1;
	sort(P+1,P+1+n,cmp);
	for(int i=1;i<=n;i++)
	{
		while(now<=n&&P[now].l==i)
		{
			if(BIT.Query(P[now].id-1)) return true;
			now++;
		}
		BIT.Add(posr[i],1);
	}
	return false;
}
int main() {
//	freopen("fly.in","r",stdin);
//	freopen("fly.out","w",stdout);
	read(n);
	for(int i=1,x;i<=n;i++) read(x),L[0][0][i]=max(1,i-x),R[0][0][i]=min(n,i+x);
	for(int i=1,j=2;j<=n;i++,j<<=1)
	{
		for(int l=1;l+j-1<=n;l++)
		{
			L[0][i][l]=min(L[0][i-1][l],L[0][i-1][l+(j>>1)]);
			R[0][i][l]=max(R[0][i-1][l],R[0][i-1][l+(j>>1)]);
		}
	}
	for(int I=1;I<=18;I++)
	{
		for(int J=1;J<=n;J++)
		{
			L[I][0][J]=QueryL(I-1,L[I-1][0][J],R[I-1][0][J]);
			R[I][0][J]=QueryR(I-1,L[I-1][0][J],R[I-1][0][J]);
		}
		for(int i=1,j=2;j<=n;i++,j<<=1)
		{
			for(int l=1;l+j-1<=n;l++)
			{
				L[I][i][l]=min(L[I][i-1][l],L[I][i-1][l+(j>>1)]);
				R[I][i][l]=max(R[I][i-1][l],R[I][i-1][l+(j>>1)]);
			}
		}
	}
	int l=1,r=n,Ans=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid)) l=mid+1,Ans=mid;
		else r=mid-1;
	}
	printf("%d",Ans+1);
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。
*/

智巧灵蕈大竞逐

\(~~~~\) 什么人出的题不用我多说了吧。

题意

\(~~~~\) 一个 \(n\times m\) 的矩阵,字符集大小为 \(62\)。三种操作:交换两个四联通的单元格,顺时针旋转一个 \(2\times 2\) 的子矩阵,将一个 \(n_i\times m_i\) 的子矩阵替换为预先给出的 \(k\) 个矩阵中的第 \(i\) 个矩阵。求构造最多 \(4\times 10^5\) 次操作,最多 \(400\) 次覆盖操作的方案使得其变为目标矩阵,或说明无解。
\(~~~~\) \(1\leq n,m,k\leq 20\).

题解

\(~~~~\) 考场想出来然后写不出来自闭。

\(~~~~\) 显然旋转操作可以被替换,所以只做交换。交换的时候也可以写一个函数实现矩阵内两个单独元素的交换,这样的操作次数大约是 \(\mathcal{O(2nm)}\) 的。

\(~~~~\) 接下来是替换的运用。考虑倒着做这个过程,考虑若一个矩阵是刚刚替换过来的,那目标矩阵里一定有一个子矩阵与它相同,那就替换这个子矩阵。而我们不关心在替换之前是啥,所以直接换成通配符即可。而为了凑这个子矩阵,我们可以把满足要求的都丢到左上角。替换完成后在之后的过程中通配符也可以去匹配子矩阵。

\(~~~~\) 最后只要满足当前反向处理过的目标矩阵的通配符足够表示出初始矩阵即可。

代码
查看代码
#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;
}
int n,m,K;
char rev[200];
int To[200],id;
char str[25];
int S[25][25],T[25][25];
struct oper{
    int op,x,y;
    oper(){}
    oper(int Op,int X,int Y){op=Op,x=X,y=Y;}
};
struct Matrix{
	int n,m;
	int s[25][25];
}P[25];
vector <oper> Ans;
void Swap(int X1,int Y1,int X2,int Y2)
{
    // cout<<X1<<" "<<Y1<<" "<<X2<<" "<<Y2<<endl;
    if(T[X1][Y1]==T[X2][Y2]) return;
    swap(T[X1][Y1],T[X2][Y2]);
    int TmpX=X2,TmpY=Y2,lstx=0,lsty=0;
    while(X2>X1) Ans.push_back(oper(-4,X2,Y2)),lstx=X2,lsty=Y2,X2--;
    while(X2<X1) Ans.push_back(oper(-3,X2,Y2)),lstx=X2,lsty=Y2,X2++;
    while(Y2>Y1) Ans.push_back(oper(-2,X2,Y2)),lstx=X2,lsty=Y2,Y2--;
    while(Y2<Y1) Ans.push_back(oper(-1,X2,Y2)),lstx=X2,lsty=Y2,Y2++;

	/*回去的路径必须先Y再X*/
    while(lsty>TmpY) Ans.push_back(oper(-2,lstx,lsty)),lsty--;
    while(lsty<TmpY) Ans.push_back(oper(-1,lstx,lsty)),lsty++;
    while(lstx>TmpX) Ans.push_back(oper(-4,lstx,lsty)),lstx--;
    while(lstx<TmpX) Ans.push_back(oper(-3,lstx,lsty)),lstx++;
//    for(int i=1;i<=n;i++)
//	{
//		for(int j=1;j<=m;j++) cerr<<rev[T[i][j]];
//		cerr<<endl;
//	}
//	cerr<<"==="<<endl;
}
void Print()
{
    printf("%d\n",(int)Ans.size());
    for(int i=Ans.size()-1;i>=0;i--) printf("%d %d %d\n",Ans[i].op,Ans[i].x,Ans[i].y);
    exit(0);
}
int cnt1[100],cnt2[100];
bool checkEnd()
{
	for(int i=1;i<=id+1;i++) cnt1[i]=cnt2[i]=0;
	int tot=0;
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cnt2[S[i][j]]++;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(T[i][j]>id) tot++;
			else if(cnt2[T[i][j]]) cnt2[T[i][j]]--;
		}
	}
	for(int i=1;i<=id;i++)
	{
		if(cnt2[i]>tot) return false;
		tot-=cnt2[i];
	}
	return true;
}
bool checkMatrix(int x)
{
	for(int i=1;i<=id+1;i++) cnt1[i]=cnt2[i]=0;
	int tot=0,one=0;
	for(int i=1;i<=P[x].n;i++) for(int j=1;j<=P[x].m;j++) cnt2[P[x].s[i][j]]++;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(T[i][j]>id) tot++;
			else if(cnt2[T[i][j]]) cnt2[T[i][j]]--,one++;
		}
	}
	if(!one) return false;
	for(int i=1;i<=id;i++)
	{
		if(cnt2[i]>tot) return false;
		tot-=cnt2[i];
	}
	return true;
}
void Add(int N,int M,int &x,int &y){y++;if(y==M+1) x++,y=1;}
int main() {
//	freopen("fungus.in","r",stdin);
//	freopen("fungus.out","w",stdout);
	read(n);read(m);read(K);
	for(int i='0';i<='9';i++) To[i]=++id,rev[id]=i;
	for(int i='a';i<='z';i++) To[i]=++id,rev[id]=i;
	for(int i='A';i<='Z';i++) To[i]=++id,rev[id]=i;
	rev[id+1]='*';
	for(int i=1;i<=n;i++)
	{
		scanf("%s",str+1);
		for(int j=1;j<=m;j++) S[i][j]=To[(int)str[j]];
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%s",str+1);
		for(int j=1;j<=m;j++) T[i][j]=To[(int)str[j]];
	}
	for(int i=1;i<=K;i++)
	{
		read(P[i].n);read(P[i].m);
		for(int j=1;j<=P[i].n;j++)
		{
			scanf("%s",str+1);
			for(int k=1;k<=P[i].m;k++) P[i].s[j][k]=To[(int)str[k]];
		}
	}
	while(!checkEnd())
	{
		bool move=false;
		for(int qwq=1;qwq<=K;qwq++)
		{
			if(!checkMatrix(qwq)) continue;
			move=true;
			for(int i=1;i<=id+1;i++) cnt1[i]=cnt2[i]=0;
			for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cnt2[T[i][j]]++;
			int nowx=1,nowy=1;
			while(nowx<=P[qwq].n)
			{
				int Aim;
				if(cnt2[P[qwq].s[nowx][nowy]]) Aim=P[qwq].s[nowx][nowy],cnt2[P[qwq].s[nowx][nowy]]--;
				else Aim=id+1;
				bool suc=false;
				for(int j=1;j<nowx;j++)
				{
					for(int k=P[qwq].m+1;k<=m;k++)
					{
						if(T[j][k]==Aim)
						{
							suc=true;
							Swap(j,k,nowx,nowy);
							break;
						}
					}
					if(suc) break;
				} 
				if(!suc)
				{
					for(int j=nowy+1;j<=m;j++)
					{
						if(T[nowx][j]==Aim)	
							{suc=true;Swap(nowx,j,nowx,nowy);break;}	
					}	
				}
				if(!suc)
				{
					for(int j=nowx+1;j<=n;j++)
					{
						for(int k=1;k<=m;k++)
						{
							if(T[j][k]==Aim)
							{
								suc=true;
								Swap(j,k,nowx,nowy);
								break;
							}
						}
						if(suc) break;
					}
				}
				Add(P[qwq].n,P[qwq].m,nowx,nowy);
			}
			Ans.push_back(oper(qwq,1,1));
			for(int i=1;i<=P[qwq].n;i++) for(int j=1;j<=P[qwq].m;j++) T[i][j]=id+1;
			// for(int i=1;i<=n;i++)
			// {
			// 	for(int j=1;j<=m;j++) cerr<<rev[T[i][j]];
			// 	cerr<<endl;
			// }
			// cerr<<"==="<<endl;
		}
		if(!move) return puts("-1")&0;
	}
	for(int i=1;i<=id;i++) cnt1[i]=cnt2[i]=0;
	vector <int> V;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(T[i][j]<=id) cnt2[T[i][j]]++;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			int Aim;
			if(cnt2[S[i][j]]) Aim=S[i][j],cnt2[S[i][j]]--;
			else Aim=id+1;
			bool suc=false;
			for(int k=j+1;k<=m;k++)
			{
				if(T[i][k]==Aim)
				{
					Swap(i,k,i,j);
					suc=true; break;
				}
			}
			if(!suc)
			{
				for(int k=i+1;k<=n;k++)
				{
					for(int l=1;l<=m;l++)
					{
						if(T[k][l]==Aim)
						{
							Swap(k,l,i,j);
							suc=true;break;
						}
					}
					if(suc) break;
				}
			}
		}
	}
	Print();
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。
*/
/*
那还是重构吧 
3 3 1
OOO
GOG
BGB

OOO
GGG
BBB

3 1
B
G
B
*/

贪玩蓝月

题意

\(~~~~\) 一个双端队列,操作为:在首/尾加入二元组 \((w,v)\),删除首/尾元素,查询选择一些元素使得 \(\sum w\bmod p\in[l,r]\) 且 \(\sum v\) 最大。(\(p\) 提前给定。)
\(~~~~\) \(1\leq n\leq 5\times 10^4,p\leq 500\).

题解

\(~~~~\) 一个非常套路的双栈维护双端队列。两个栈,首加入/删除就在第一个栈操作,否则就在第二个栈操作。当某个栈删空了之后就把另一个栈的元素分一半过来。查询的时候枚举一个栈的 \(\sum w \bmod p\),然后计算出另一个栈的对应合法区间,ST表做即可。那么我们就只需要在栈里维护从底到顶的背包数组即可。

\(~~~~\) 由于分一半那就是减半警报器类似物,所以分一半的操作只会有 \(\log n\) 次,那最后复杂度在 \(\mathcal{O(np\log n)}\) 了。

代码
查看代码
#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;
}
char op[10];
struct node{
	ll Ans[505];
	node(){memset(Ans,0,sizeof(Ans));}
}Sta1[50005],Sta2[50005];
PII S1[50005],S2[50005],STmp[50005];
int p,Top1,Top2,Top;
void Add1(PII P)
{ 
	int w,x;w=P.first; x=P.second;
	Top1++; w%=p; S1[Top1]=mp(w,x);
	for(int i=0;i<p;i++) Sta1[Top1].Ans[(i+w)%p]=max(Sta1[Top1-1].Ans[i]+x,Sta1[Top1-1].Ans[(i+w)%p]);
}
void Add2(PII P)
{
	int w,x;w=P.first; x=P.second;
	Top2++; w%=p; S2[Top2]=mp(w,x);
	for(int i=0;i<p;i++) Sta2[Top2].Ans[(i+w)%p]=max(Sta2[Top2-1].Ans[i]+x,Sta2[Top2-1].Ans[(i+w)%p]);
}
int n,lg[505];
ll f[10][505];
void Init(node a)
{
	for(int i=0;i<p;i++) f[0][i]=a.Ans[i];
	for(int i=1;i<=9;i++)
		for(int j=0;j+(1<<i)-1<p;j++) f[i][j]=max(f[i-1][j],f[i-1][j+(1<<(i-1))]);
}
ll Query(int l,int r)
{
	int t=__lg(r-l+1);
	return max(f[t][l],f[t][r-(1<<t)+1]);
}
int main() {
//	freopen("tanwan3.in","r",stdin);
	int ID;read(ID);lg[0]=-1;
	for(int i=1;i<=500;i++) lg[i]=lg[i>>1]+1;
	int w,x,l,r;read(n);read(p);
	for(int i=1;i<p;i++) Sta1[Top1].Ans[i]=Sta2[Top2].Ans[i]=-1e18;
	while(n--)
	{
		scanf("%s",op+1);
		if(op[1]=='I'&&op[2]=='F') read(w),read(x),Add1(mp(w,x));
		if(op[1]=='I'&&op[2]=='G') read(w),read(x),Add2(mp(w,x));
		if(op[1]=='D'&&op[2]=='F')
		{
			if(!Top1) while(Top2) Add1(S2[Top2--]);
			Top1--;
		}
		if(op[1]=='D'&&op[2]=='G')
		{
			if(!Top2) while(Top1) Add2(S1[Top1--]);
			Top2--;
		}
		if(op[1]=='Q')
		{
			read(l);read(r);
			if(!Top1&&!Top2)
			{
				if(l>0) puts("-1");
				else puts("0");
				continue;
			}
			node res=Sta1[Top1];
			Init(Sta2[Top2]);
			ll Ans=max(-1ll,Query(l,r));
			for(int i=0;i<p;i++)
			{
				int L=(l-i+p)%p,R=(r-i+p)%p;	
				if(res.Ans[i]<=-1e9) continue;
				else if(L<=R) Ans=max(Ans,Query(L,R)+res.Ans[i]);
				else Ans=max(Ans,max(Query(0,R),Query(L,p-1))+res.Ans[i]);
			}
			printf("%lld\n",Ans);
		}
		if(!Top1&&Top2>1)
		{
			Top=0;
			while(Top2>Top) STmp[++Top]=S2[Top2--];
			while(Top2) Add1(S2[Top2--]);
			while(Top) Add2(STmp[Top--]);
		}
		if(!Top2&&Top1>1)
		{
			Top=0;
			while(Top1>Top) STmp[++Top]=S1[Top1--];
			while(Top1) Add2(S1[Top1--]);
			while(Top) Add1(STmp[Top--]);
		}
	}
	return 0;
}
/*
瑶草一何碧,春入武陵溪。溪上桃花无数,花上有黄鹂。我欲穿花寻路,直入白云深处,浩气展虹霓。只恐花深里,红露湿人衣。
坐玉石,欹玉枕。拂金徽。谪仙何处,无人伴我白螺杯。我为灵芝仙草,不为朱唇丹脸,长啸亦何为。醉舞下山去,明月逐人归。

双栈背包是好东西啊 
2
20 349
QU 297 305
IF 30976 29887
IG 22276 21153
DG
IF 29940 29024
QU 101 182
QU 68 226
IF 31798 1737
DF
DG
QU 0 5
QU 144 152
DG
QU 234 312
IG 8605 11859
QU 39 327
DF
IF 11919 23584
QU 157 329
IF 22792 13890

-1
-1
58911
0
-1
-1
11859
-1
*/

标签:ch,int,矩阵,2023.3,--,while,27,Ans
From: https://www.cnblogs.com/Azazel/p/17263305.html

相关文章

  • 总结20230327
    今天上的是工程数学和软件工程。工程数学课上学的是点的可行方向简称FD等等知识点,我感觉这节课听得很认真,听课效率也极高,能高达百分之八十五。下午的软件工程这节课定下......
  • 3.27软件工程学习总结
    今天上午学习了android端的地铁查询,由于这个结对作业,主要代码程序在队友的电脑上,通过在自己电脑上的一些调试,完成了整个项目的运行,期间遇到了android虚拟机上不能用中文......
  • 3.27每日总结
    <!DOCTYPEhtml><html><head><title>信2105-2杨帅飞的个人主页</title><metahttp-equiv="content-type"content="text/html;charset=UTF-8"><styletype="t......
  • 2023.3.27
    整理了一点状压。拜托,但是我的状压真的学的和个什么东西一样啊。AcWing 91.最短Hamilton路径 1#include<bits/stdc++.h>2usingnamespacestd;3constint......
  • 2023.3.27阅读笔记
    《代码大全》阅读笔记01 欢迎进入软件构建的世界这章阐述了软件构建的重要性,软件构建大体上就是说具体程序员做的工作,而不是需求收集人员,产品设计人员,业务分析人员,......
  • 云原生周刊:K8s 在 v1.27 中移除的特性和主要变更
    文章推荐K8s在v1.27中移除的特性和主要变更随着Kubernetes发展和成熟,为了此项目的整体健康,某些特性可能会被弃用、移除或替换为优化过的特性。基于目前在v1.27发......
  • 闲话 23.3.27
    闲话某人写了INTERNETYAMERO上黑板……我觉得会被跳过另一个人写了BrainPower上黑板A老师:这玩意有词?美式咖啡喝凉的好还是热的好?模拟赛这模拟赛打的明天是......
  • 代码随想录 day27 39. 组合总和 | 40.组合总和II | 131.分割回文串
    39. 组合总和给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的所有 不同组合 ,并以列......
  • 2023.3.27-构建之法-3月份读后感1
    最近,我阅读了构建之法的一部分,我有了一些感受。过去我对于软件工程的了解不够深入,对于“程序=数据结构+算法”这句话的理解不够深入。构建管理、源代码管理、软件设计、......
  • 【2023.03.27】乐乐兄弟中华街系列8962短评
    前言本人是自费购买积木,购买原因是给妹妹培养动手能力,减少短视频占用时间,其次是给家里做摆饰,所以选择积木多考虑了美观非专业评测,如果想看更多积木评测请点进我的博客主......