zoukankan      html  css  js  c++  java
  • noip模拟64

    考试过程:这次考试觉得自己发挥不错,就是还是有一些没想到。
    首先是T1,看到数据范围我觉得正解应该是\(o(n^3)\)的,于是就往这个方面想,想到了并查集,但是利用并查集需要把矩形里面的除去,我当时觉得这种方法不太可行,就换了一种。
    想到了枚举小矩形后再从小矩形四个边上向外扩展,最后求和,但是我算错复杂度了,这样是\(o(n^4)\)的。
    然而正解是将我的两个思路合在一起(难受及了)。
    然后是T2,凭直觉我觉得是一个\(dp\),而且看数据范围我觉得\(dp\)方程应该长这个样子\(f_i=max(f_j+1)\),
    然后我就想了想,真的退出来了,这样复杂度是\(o(n^2)\)的,可以获得\(50pts\),但是我的方程获得了\(70pts\),比别人多\(20pts\),可能是我的一些剪枝。
    然后想优化,写写式子就发现是个\(CDQ\)分治的板子题,然后就切了。
    T3,T4觉得不太可做,就想打暴力,结果没什么时间了,后两题就没得到什么分,这点以后需要注意,无论什么题,基础分必须要拿到。

    T1 网格图

    思路:
    image
    说一下这个计算的过程,我们对于每一行,先枚举一个\(k\times k\)的矩形,暴扫,然后将矩形内部的点所属的并查集的\(size--\),然后我们扫这个矩形的上下左右四个边界,加上他们所在的并查集的大小,最后再加上\(k\times k\)即可。考虑移动的话我们就要先消除之前的影响,然后添加新的影响。代码如下:

    AC_code
    
    #include<bits/stdc++.h>
    #define re register int
    #define ii inline int
    #define iv inline void
    #define mid ((l+r)>>1)
    #define lc (rt<<1)
    #define rc (rt<<1|1)
    #define f() cout<<"fuck"<<endl
    #define head headddd
    #define next net
    #define F first
    #define S second
    using namespace std;
    const int N=510;
    const int M=3e5+10;
    int n,k,ans,timi;
    char ch[N][N];
    int pos[N][N],size[M],use[M];
    pair<int,int> be[N][N];
    bool vis[N][N];
    ii read()
    {
    	int x=0;char ch=getchar();bool f=1;
    	while(ch<'0' or ch>'9')
    	{
    		if(ch=='-') f=0;
    		ch=getchar();
    	}
    	while(ch>='0' and ch<='9')
    	{
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return f?x:(-x);
    }
    iv dfs(int x,int y,int fx,int fy)
    {
    	be[x][y]=make_pair(fx,fy);
    	vis[x][y]=1;
    	size[pos[fx][fy]]++;
    	if(x-1>0 and ch[x-1][y]=='.' and !vis[x-1][y])
    		dfs(x-1,y,fx,fy);
    	if(x+1<=n and ch[x+1][y]=='.' and !vis[x+1][y])
    		dfs(x+1,y,fx,fy);
    	if(y-1>0 and ch[x][y-1]=='.' and !vis[x][y-1])
    		dfs(x,y-1,fx,fy);
    	if(y+1<=n and ch[x][y+1]=='.' and !vis[x][y+1])
    		dfs(x,y+1,fx,fy); 
    }
    signed main()
    {
    	freopen("grid.in","r",stdin),freopen("grid.out","w",stdout);
    	n=read(),k=read();
    	for(re i=1;i<=n;i++)
    		scanf("%s",ch[i]+1);
    	for(re i=1;i<=n;i++)
    	{
    		for(re j=1;j<=n;j++)
    		{
    			pos[i][j]=(i-1)*500+j;
    			be[i][j]=make_pair(i,j);	
    		}
    	}
    	for(re i=1;i<=n;i++)
    	{
    		for(re j=1;j<=n;j++)
    			if(!vis[i][j] and ch[i][j]=='.')
    				dfs(i,j,i,j);
    	}
    	bool flag=1;
    	int cd=0,tmp=0;
    	for(re i=1;i+k<=n+1;i++)
    	{
    		tmp=0;
    		++timi;
    		for(re j=i;j<=i+k-1;j++)//暴扫
    		{
    			for(re p=1;p<=k;p++)
    				size[pos[be[j][p].F][be[j][p].S]]--;
    		}
    		if(i-1>0)
    		{
    			for(re p=1;p<=k;p++)
    			{
    				if(ch[i-1][p]=='.')
    				{
    					if(use[pos[be[i-1][p].F][be[i-1][p].S]]!=timi) tmp+=size[pos[be[i-1][p].F][be[i-1][p].S]];
    					use[pos[be[i-1][p].F][be[i-1][p].S]]=timi;
    				} 
    			}
    		}
    		if(i+k<=n)
    		{
    			for(re p=1;p<=k;p++)
    			{
    				if(ch[i+k][p]=='.')
    				{
    					if(use[pos[be[i+k][p].F][be[i+k][p].S]]!=timi) tmp+=size[pos[be[i+k][p].F][be[i+k][p].S]];
    					use[pos[be[i+k][p].F][be[i+k][p].S]]=timi;
    				} 
    			}
    		}
    		if(1+k<=n)
    		{
    			for(re p=i;p<=i+k-1;p++)
    			{
    				if(ch[p][1+k]=='.')
    				{
    					if(use[pos[be[p][1+k].F][be[p][1+k].S]]!=timi) tmp+=size[pos[be[p][1+k].F][be[p][1+k].S]];
    					use[pos[be[p][1+k].F][be[p][1+k].S]]=timi;
    				}
    			}
    		}
    		ans=max(ans,tmp+k*k);
    		for(re j=2;j+k<=n+1;j++)
    		{
    			tmp=0;
    			++timi;
    			for(re p=i;p<=i+k-1;p++) //消除影响
    				size[pos[be[p][j-1].F][be[p][j-1].S]]++;
    			for(re p=i;p<=i+k-1;p++)//加入新列
    				size[pos[be[p][j+k-1].F][be[p][j+k-1].S]]--;
    			if(i-1>0)
    			{
    				for(re p=j;p<=j+k-1;p++)
    				{
    					if(ch[i-1][p]=='.')
    					{
    						if(use[pos[be[i-1][p].F][be[i-1][p].S]]!=timi) tmp+=size[pos[be[i-1][p].F][be[i-1][p].S]];
    						use[pos[be[i-1][p].F][be[i-1][p].S]]=timi;
    					} 
    				}
    			}
    			if(i+k<=n)
    			{
    				for(re p=j;p<=j+k-1;p++)
    				{
    					if(ch[i+k][p]=='.')
    					{
    						if(use[pos[be[i+k][p].F][be[i+k][p].S]]!=timi) tmp+=size[pos[be[i+k][p].F][be[i+k][p].S]];
    						use[pos[be[i+k][p].F][be[i+k][p].S]]=timi;
    					} 
    				}
    			}
    			if(j-1>0)
    			{
    				for(re p=i;p<=i+k-1;p++)
    				{
    					if(ch[p][j-1]=='.')
    					{
    						if(use[pos[be[p][j-1].F][be[p][j-1].S]]!=timi) tmp+=size[pos[be[p][j-1].F][be[p][j-1].S]];
    						use[pos[be[p][j-1].F][be[p][j-1].S]]=timi;
    					}
    				}
    			}
    			if(j+k<=n)
    			{
    				for(re p=i;p<=i+k-1;p++)
    				{
    					if(ch[p][j+k]=='.')
    					{
    						if(use[pos[be[p][j+k].F][be[p][j+k].S]]!=timi) tmp+=size[pos[be[p][j+k].F][be[p][j+k].S]];
    						use[pos[be[p][j+k].F][be[p][j+k].S]]=timi;
    					}
    				}
    			}
    			ans=max(ans,tmp+k*k);
    		}
    		for(re j=i;j<=i+k-1;j++)//暴扫还原
    			for(re p=n-k+1;p<=n;p++)
    				size[pos[be[j][p].F][be[j][p].S]]++;
    	}
    	printf("%d\n",ans);
    	return 0;
    }
    
    
    

    T2 序列问题

    思路:简单的\(dp\)题,\(CDQ\)分治裸题。反正我觉得是这样
    \(f_i\)表示以\(i\)结尾,并且\(i\)是满足条件的序列的最大长度,那么状态转移方程为\(f_i=max(f_i,f_j+1)\),注意\(j<i,a_j<a_i,i-a_i>=j-a_j\),这样的话明显的三维偏序问题真的很\(CDQ\),随便打打就过了,注意线段树要用\(n\),不要用离散化后的\(cnt\).代码如下:

    AC_code
    
    
    
    #include<bits/stdc++.h>
    #define re register int
    #define ii inline int
    #define iv inline void
    #define f() cout<<"fuck"<<endl
    #define head headddd
    #define next net
    using namespace std;
    const int N=5e5+10;
    int n,ans,cnt;
    int a[N],lsh[N];
    int f[N];
    struct node
    {
    	int a,pos;
    }cun[N];
    ii read()
    {
    	int x=0;char ch=getchar();bool f=1;
    	while(ch<'0' or ch>'9')
    	{
    		if(ch=='-') f=0;
    		ch=getchar();
    	}
    	while(ch>='0' and ch<='9')
    	{
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return f?x:(-x);
    }
    inline bool com1(node x,node y)
    {
    	if(x.a!=y.a) return x.a<y.a;
    	return x.pos<y.pos;
    }
    inline bool com2(node x,node y)
    {
    	return x.pos<y.pos;
    }
    struct Segment_Tree
    {
    	#define mid ((l+r)>>1)
    	#define lc (rt<<1)
    	#define rc (rt<<1|1)
    	int maxx[N<<2];
    	iv pp(int rt)
    	{
    		maxx[rt]=max(maxx[lc],maxx[rc]);
    	}
    	iv reset(int rt,int l,int r)
    	{
    		maxx[rt]=0;
    		if(l==r) return;
    		reset(lc,l,mid),reset(rc,mid+1,r);
    		pp(rt);
    	}
    	iv clear(int rt,int l,int r,int p)
    	{
    		if(l==r)
    		{
    			maxx[rt]=0;
    			return;
    		}
    		if(mid>=p) clear(lc,l,mid,p);
    		else clear(rc,mid+1,r,p);
    		pp(rt);
    	}
    	iv add(int rt,int l,int r,int p,int z)
    	{
    		if(l==r)
    		{
    			maxx[rt]=max(maxx[rt],z);
    			return;
    		}
    		if(mid>=p) add(lc,l,mid,p,z);
    		else add(rc,mid+1,r,p,z);
    		pp(rt);
    	}
    	ii query(int rt,int l,int r,int L,int R)
    	{
    		if(L>R) return 0;
    		if(L<=l and r<=R) return maxx[rt];
    		if(mid>=R) return query(lc,l,mid,L,R);
    		if(mid<L) return query(rc,mid+1,r,L,R);
    		return max(query(lc,l,mid,L,R),query(rc,mid+1,r,L,R));
    	}
    	#undef mid
    	#undef lc
    	#undef rc	
    }T;
    void solve(int l,int r)
    {
    	if(l==r)
    	{
    		if(l>=lsh[a[l]]) f[l]=max(f[l],1);
    		return;
    	}
    	int mid=(l+r)>>1;
    	solve(l,mid);
    	sort(cun+l,cun+mid+1,com1),sort(cun+mid+1,cun+r+1,com1);
    	int j=l,i=mid+1;
    	for(;i<=r;i++)
    	{
    		while(cun[j].a<cun[i].a and j<=mid)
    		{
    			if(cun[j].pos-lsh[cun[j].a]>=0)
    				T.add(1,0,n,cun[j].pos-lsh[cun[j].a],f[cun[j].pos]);
    			++j;
    		}
    		if(cun[i].pos-lsh[cun[i].a]>=0)
    			f[cun[i].pos]=max(f[cun[i].pos],T.query(1,0,n,0,cun[i].pos-lsh[cun[i].a])+1);
    	}
    	for(re k=l;k<j;k++) if(cun[k].pos-lsh[cun[k].a]>=0) T.clear(1,0,n,cun[k].pos-lsh[cun[k].a]);
    	sort(cun+mid+1,cun+r+1,com2);
    	solve(mid+1,r);
    }
    signed main()
    {
    	freopen("sequence.in","r",stdin),freopen("sequence.out","w",stdout);
    	n=read();
    	for(re i=1;i<=n;i++) a[i]=read(),lsh[i]=a[i];
    	sort(lsh+1,lsh+n+1);
    	cnt=unique(lsh+1,lsh+n+1)-lsh-1;
    	for(re i=1;i<=n;i++)
    	{
    		a[i]=lower_bound(lsh+1,lsh+cnt+1,a[i])-lsh;
    		cun[i]=(node){a[i],i};	
    	}
    	solve(1,n);
    	for(re i=1;i<=n;i++) ans=max(ans,f[i]);
    	printf("%d\n",ans);
    	return 0;
    }
    
    
    
  • 相关阅读:
    有关同时包含<winsock2.h>与<windows.h>头文件的问题
    如何使用微软提供的TCHAR.H头文件?
    下面的程序在VC6通过,在VS2008不能,错误信息都是“不能将参数……从const char[]转换为LPCWSTR”
    Android开发学习日志(四)
    爬虫开发(一)
    java集合源码详解
    Paxos算法
    linux 常用命令
    Bitmap的原理和应用
    Flink Checkpoint 问题排查实用指南
  • 原文地址:https://www.cnblogs.com/WindZR/p/15354408.html
Copyright © 2011-2022 走看看