Codeforces Round #619 (Div. 2) D、E

D

题意

在这里插入图片描述
从左上角开始走,不能走重复的路,走确切 k k 条路,给出方案。
方案的形式是多个 s t e p step ,每个 s t e p step 是由 x x 和不超过 4 4 的字符串组成,字符串表示怎么走, x x 即走多少个这样的字符串。
【比如 L R L R L R L R L R LRLRLRLRLR 可以表示为 4 L R 4\quad LR
要求这样的数量不超过 3000 3000

题解

比赛的时候没想到能跑满。神经石乐志。
考虑左上,能出去一次回来一次出去一次再回来一次。
如果要跑满的话必定,它要作为终点。

我们考虑对于第一列,它往下走一格,然后把第二行左右都走一遍。一直走到底。
会到 ( n , 1 ) (n,1) 的地方,并且把所有 2 n 2\to n 的左右都走了。
然后一直往上走到 ( 1 , 1 ) (1,1)

同理,往右一格,然后走满所有的上下,最后回来。

这样每次用第一列的上下换了所有的左右(除了第一行),然后用第一行的左右换了所有的上下。
一共两次,每次是 1 + 2 ( m 1 ) + n 1 + 1 1+2*(m-1)+n-1+1
所以次数是 2 ( 3 ( 500 1 ) + 2 ) 2*(3*(500-1)+2)

#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define sf(x) scanf("%d",&x)
typedef long long ll;
using namespace std;
 
const ll mod = 1e9+7;
const int maxn = 3e5+500;
 
int n,m,k;
vector<pair<int,char> >G;
 
void print(){
    puts("YES");
    cout<<G.size()<<endl;
    for(auto it:G){
        cout<<it.first<<" "<<it.second<<endl;
    }
}
 
void del(int cnt,char ch){
    if(cnt==0)return ;
    if(k<=cnt)G.push_back(make_pair(k,ch)),print(),exit(0);
    else G.push_back(make_pair(cnt,ch)),k-=cnt;
}
 
int main(){
    cin>>n>>m>>k;
    del(n-1,'D');
    for(int i=1;i<n;i++)del(m-1,'R'),del(m-1,'L'),del(1,'U');
    for(int i=1;i<m;i++)del(1,'R'),del(n-1,'D'),del(n-1,'U');
    del(m-1,'L');
    puts("NO");
}

E

题意

对于一个四色矩阵,多个询问,询问子矩阵中最大的四色块
四色块是:
在这里插入图片描述

题解

首先我们得求出有哪些四色块,我们可以以中间点为标志代表一个四色块,比如红色右下角。
怎么快速求对于每个方块作为中心点的时候能得到的最大四色块呢?
首先枚举每个方块是 n 2 n^2 。其实我们可以暴力扩展,维护一个二维前缀和判断 8 8 个长条,比如红色就是左边和上边必须是红色,一层一层往外扩展。复杂度是 n 3 n^3
我们发现四色块肯定是越大越可能不符合,越小越可能符合,并且一旦符合小的一定符合。
所以我们可以二分。

再考虑怎么快速求子矩阵中最大四色块,首先我们知道上面那个值,但是他可能会超过子矩阵大小,所以边界是一定限制的。这里也用到了二分(我觉得比较巧妙)。
二分答案,从而确定了中心点的范围,比如询问 2   2   6   6 2 \ 2\ 6\ 6 ,你需要判断 3 3 是不是答案。
首先中心点一旦在 3   3 3 \ 3 ,肯定不是答案,哪怕他能形成 3 \geq 3 的四色块。因为边界限制了它。他的答案最多也只是 2 2

所以在我们判断答案 m i d mid 合法与否的时候,上左边界应该是 x m i d + 1 x-mid+1 ,下右边界应该是 x m i d x-mid ,这样能够保证不会被边界限制,判断此时新的子矩阵中的最大值,如果大于等于 m i d mid 说明能取到答案。

显然 m i d mid 越大,新子矩阵范围越小,最大值越小; m i d mid 越小,新矩阵范围变大,最大值越大,显然一定满足要求。
至于矩阵最值,用二维 r m q rmq (原理就是二维分别一维 r m q rmq )

#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define sf(x) scanf("%d",&x)
typedef long long ll;
using namespace std;
 
const ll mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const int maxn = 3e5+500;
 
int n,m,q;
const int Log = 12;
const int N = 600;
int maxv[Log][Log][N][N];
int pre[N],val[N][N],sum[N][N][4];
char str[N][N];
 
void init(){
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)maxv[0][0][i][j]=val[i][j];
	pre[2]=pre[3]=1;
	for(int i=4,up=max(n,m);i<=up;i++)pre[i]=pre[i>>1]+1;
	int up1=pre[n]+1,up2=pre[m]+1;
	for(int l1=0;l1<=up1;l1++){
		for(int l2=0;l2<=up2;l2++){
			if(!l1&&!l2) continue;
			for(int i=1;(i+(1<<l1)-1)<=n;i++){
				for(int j=1;(j+(1<<l2)-1)<=m;j++){
					if(l2)maxv[l1][l2][i][j]=max(maxv[l1][l2-1][i][j],maxv[l1][l2-1][i][j+(1<<(l2-1))]);
					else maxv[l1][l2][i][j]=max(maxv[l1-1][l2][i][j],maxv[l1-1][l2][i+(1<<(l1-1))][j]);
				}
			}
		}
	}
}
 
int query(int x1,int y1,int x2,int y2){
	int p=pre[x2-x1+1],q=pre[y2-y1+1];
	int ans=-inf;
	ans=max(maxv[p][q][x1][y1],maxv[p][q][x1][y2-(1<<q)+1]);
	ans=max(ans,max(maxv[p][q][x2-(1<<p)+1][y1],maxv[p][q][x2-(1<<p)+1][y2-(1<<q)+1]));
	return ans;
}
 
bool check(int x1,int x2,int y1,int y2){
    if(x1>=1&&x1<=n)
    if(x2>=1&&x2<=n)
    if(y1>=1&&y1<=m)
    if(y2>=1&&y2<=m)return true;
    return false;
}
 
int getsum(int x1,int y1,int x2,int y2,int id){
    if(!check(x1,x2,y1,y2))return 0;
    return sum[x2][y2][id]-sum[x1-1][y2][id]-sum[x2][y1-1][id]+sum[x1-1][y1-1][id];
}
 
bool checkval(int x,int y,int L){
    int x1,y1,x2,y2;
    x1=x-L+1,y1=y-L+1,x2=x,y2=y;
    if(getsum(x1,y1,x2,y2,0)<L*L)return false;
    x1=x-L+1,y1=y+1,x2=x,y2=y+L;
    if(getsum(x1,y1,x2,y2,1)<L*L)return false;
    x1=x+1,y1=y-L+1,x2=x+L,y2=y;
    if(getsum(x1,y1,x2,y2,2)<L*L)return false;
    x1=x+1,y1=y+1,x2=x+L,y2=y+L;
    if(getsum(x1,y1,x2,y2,3)<L*L)return false;
    return true;
   // cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl;
  //  cout<<getsum(x1,y1,x2,y2,0)<<endl
}
 
bool checkans(int x1,int y1,int x2,int y2,int mid){
  //  cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<" "<<mid<<endl;
    if(x1<=x2&&y1<=y2){
        if(query(x1,y1,x2,y2)>=mid)return true;
        else return false;
    }
    else return false;
}
 
int main(){
    cin>>n>>m>>q;
    FOR(i,1,n)scanf("%s",str[i]+1);
    FOR(i,1,n)FOR(j,1,m){
        FOR(k,0,3)sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k];
        if(str[i][j]=='R')sum[i][j][0]++;
        if(str[i][j]=='G')sum[i][j][1]++;
        if(str[i][j]=='Y')sum[i][j][2]++;
        if(str[i][j]=='B')sum[i][j][3]++;
    }
    for(int i=1;i<n;i++){
        for(int j=1;j<m;j++){
            int l=0,r=min(n,m),ans;
            while(l<=r){
                int mid=(l+r)>>1;
                if(checkval(i,j,mid)){
                    l=mid+1;
                    ans=mid;
                }
                else r=mid-1;
            }
            val[i][j]=ans;
            //cout<<val[i][j]<<" ";
        }
        //cout<<endl;
    }
    init();
    for(int i=1;i<=q;i++){
        int x1,y1,x2,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        int l=0,r=min(n,m),ans;
        while(l<=r){
            int mid=(l+r)>>1;
            if(checkans(x1+mid-1,y1+mid-1,x2-mid,y2-mid,mid)){
                l=mid+1;
                ans=4*mid*mid;
            }
            else r=mid-1;
        }
        printf("%d\n",ans);
    }
}
发布了203 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/mxYlulu/article/details/104310048
今日推荐