2021杭电多校1

Source

比赛情况:
在这里插入图片描述
过程:cqf签了1001,1005,然后wmd莫队过了1010。之后我和cqf干过去了1008。后面cqf和wmd过了1009,我最后过了1006;

T1008 Maximal submatrix

在这里插入图片描述

题意:给定一个N*M的矩阵,求一个面积最大的子矩阵,且子矩阵每一列从上到下的数值是不下降的

idea:这题一开始想麻烦了,导致卡了比较久。我们可以转化成这个模型在这里插入图片描述
这个模型只需要左右各跑一遍单调栈就行了。
我们可以以每一行作为最底下那一排,跑一遍这个模型。当然需要先预处理出每一个格子往下连续的还有几个比它大。

ACcode:

#include<bits/stdc++.h>
#define LL long long 
#define N 2050
#define MIN 0xc0c0c0c0
using namespace std;
int a[2050][2050],p[2050][2050],ans = MIN,maxx  = 0;

void ww()
{
    
      
	ans = 0;
	int n,m;
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&a[i][j]),p[i][j]=1;
	for (int i=n-1;i>=1;i--) for (int j=1;j<=m;j++) if (a[i][j]<=a[i+1][j]) p[i][j]=p[i+1][j]+1;
	
	int h[N],l[N],r[N],q[N];
	for(int z=1;z<=n;z++)
	{
    
      
		maxx = 0;
		int tt = 0;
		q[0] = 0;
		p[z][0] = p[z][m+1] = -1;
		for(int i=1;i<=m;i++)
		{
    
      
			while( p[z][i] <= p[z][ q[tt] ] ) tt--;
			l[ i ] = q[tt];
			q[ ++tt ] = i;
		}
		tt = 0;
		q[0] = m+1;
		for(int i=m;i>=1;i--)
		{
    
      
			while( p[z][i] <= p[z][ q[tt] ] ) tt--;
			r[i] = q[tt];
			q[ ++tt ] = i;
		}
		for(int i=1;i<=m;i++)
		{
    
      
			maxx = max( maxx , p[z][i]*( r[i]-l[i]-1 ) );
		}
		ans = max( maxx , ans );
	}
	printf("%d\n",ans);
	
}
int main()
{
    
      
	//freopen("in.txt","r",stdin);
	int t;
	scanf("%d",&t);
	while (t)
	{
    
      
		t--;
		
		ww();	
	}
}

T1006 Xor sum

在这里插入图片描述
在这里插入图片描述

题意:给一个长度为n的序列,再给定一个k,求一个最短的(同样长度找最靠左的)连续的子序列,是的子序列里面的值异或起来之后大于等于k,没有输出-1。

idea:数列做前缀异或,将题面转化为找两个距离最近的数,使得他们的异或值不小于k。
枚举靠右的那个数,同时维护01字典树,字典树每个节点保存范围内最靠右的点的位置。根据k来询问对应的log个节点,从而更新答案。
效率:O(nlogn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define INF 0x3f3f3f3f
#define LL long long
#define N 100100
using namespace std;

int tr[N*15][2],t,n,a[N],x,id[N*15],idx = 0,l,r,minn,k,len,b[N];
inline int read()
{
    
      
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){
    
      if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}


void insert( int pp , int x )
{
    
      
	int p = 0;
	for(int i=30;i>=0;i--)
	{
    
      
		if( !tr[p][ ((x>>i) & 1 )] )
		{
    
      
			idx++;
			tr[p][ ((x>>i) & 1 )] = idx;
		}
		p = tr[p][ ((x>>i) & 1 )];
	}
	id[ p ] = pp;
}

int search( int x )
{
    
      
	int p = 0;
	for(int i=30;i>=0;i--)
	{
    
      
		int s = ((x>>i) & 1);
		if( tr[p][!s] ) p = tr[p][!s];
		else p = tr[p][s];
	}
	return id[p];
}

void solve(  )
{
    
      
	memset(tr,0,sizeof(tr));
	//memset(id,0,sizeof(id));
	len = INF;
	minn = INF;
	l = -1,r = n+1;
	idx = 0;
	n = read();
	k = read();
	for(int i=1;i<=n;i++)
	{
    
      
		b[i] = read();
		a[i] = b[i] ^ a[i-1];
	}
	insert( 0 , a[0] );
	for(int i=1;i<=n;i++)
	{
    
      
		int j = search( a[i] );
		int temp1 = b[i];
		int temp2 = a[j] ^ a[i];
		int ll = j+1,rr = i;
		if( temp1>=k )
		{
    
      
			l = r = i;
			break;
		}
		else if( temp2 >= k )
		{
    
      
			if( (rr-ll+1) < len )
			{
    
      
				l = ll;
				r = rr;
				len = r-l+1;
			}
			else if( (rr-ll+1) == len )
			{
    
      
				if( ll<l )
				{
    
      
					l = ll;
					r = rr;
					len = r-l+1;
				}
			}
		}
		insert( i , a[i] );
	}
	if( l==-1 )
	{
    
      
		printf("-1\n");
	}
	else printf("%d %d\n",l,r);
}

int main()
{
    
      
	//freopen("in.txt","r",stdin);
	cin>>t;
	while( t-- )
	{
    
      
		solve();
	}
	return 0;
}

PS:比赛时评测机跑得快啊
多谢评论区两位大佬提醒,原先的代码在赛后是过不去的QWQ
稍微修改了一下数组范围,memset那部分变快了,这是上面这段代在赛后评测的结果
在这里插入图片描述
而且不用快读好像还更快