2019CSP-S模拟赛十联测day3

19CSP-S模拟赛十联测day3

link

100+0+40=140 (rk=40)

题目

A. 最长01子序列

  • n2n^2的暴力很简单,枚举中间隔着多少个零,每次O(n)O(n)检查
  • 枚举零的个数是不能省的,考虑每次检查的时候优化,出题人和大部分人的正解都是二分下一个一的位置,而我考场写的是倍增跳零,复杂度都是O(nlog2n)O(nlog^2n),但是我不知为何跑得几乎最慢

B. 路径长度

这题考场直接没写,九点钟一到就去打CFCF了,结果最后CFCF也没加几分。

  • 这题爆搜搜一搜经过试验是可以获得40分的好成绩
  • 40分的暴力也可以是对于每个点,把能到它的所有距离算出来,揹包算,据说bitset存优化常数就可以60分了
  • 正解就是发现并不需要记录到每个点所有的距离,当存在1011zxyz\frac{10}{11} z \leq x \leq y \leq zyy这个距离可以不记录,为什么?我们看看覆盖yy的询问是否可以用xxzz回答就知道了,显然包含y的询问区间必定包含xx或者zz
  • 那么每个点需要记录的个数就是O(logn)O(logn)级别的,因为log1.11e9\log_{1.1} {1e9}大概200+,我们把可以到的距离丢进数组里,就不用0/10/1了,每次暴力合并直接排序,问题不大
  • 由于保证了每条有向边x>yx->y都有x<yx<y,这就很舒适,自带拓扑序

C. 动态矩阵最短路

  • 感觉这题其实是个简单题,但是考场上没想出来
  • 对于任意一次询问,当前的局面必定是又有些列加上某些行形成网格状
  • 对于网格状的最短路情况很少我们分类讨论
  • 第一种,一个点的行和另一点的列联通,或者行列换一下,答案是曼哈顿距离
  • 第二种,两个点都有行,再加上随便一列,列如果在中间答案就是曼哈顿距离,否则更大,行列也可以换一下
  • 第三种,两点之间的所有行或所有列联通
  • 那么维护的话,就是对于行和列分别建线段树,操作包括单点修改和查询区间最值,其中第二种中需要二分来查找某个位置左起或右起第一个比某个数大的位置
  • 情况考虑全就挺好写的

代码

A. 最长01子序列 考场代码

#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(a);i>=(b);i--)
#define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
#define mem(i,j) memset(i,j,sizeof(i))
#define MP make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,a[N],nxt1[N],pos1,nxt0[21][N],pos0,ans=0;
char s[N];
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
inline void write(int x)
{
	if (x<0) putchar('-'),x=-x;
	if (x>9) write(x/10);
	putchar(x%10+'0');
	return;
}
inline int pan1()
{
	int ret=1;
	FOR(i,1,n) ret&=(a[i]==0);
	return ret;
}
inline void pan2()
{
	int cnt=0;
	FOR(i,1,n) cnt+=(a[i]==1);
	ans=max(ans,cnt);
	return;
}
inline int get0(int pos,int k)
{
	if (pos==-1) return -1;
	while (k)
	{
		int step=log2(k);
		pos=nxt0[step][pos];
		if (pos==-1) return -1;
		k-=(1<<step);
	}
	return pos;
}
inline int solve(int gap)
{
	int ret=0,pos;
	if (a[1]) pos=get0(1,gap);
	else pos=get0(1,gap-1);
	if (pos==-1) return 0;
	ret+=gap;
	while (pos!=-1)
	{
		pos=nxt1[pos];
		pos=get0(pos,gap);
		if (pos!=-1) ret+=gap+1;
	}
	return ret;
}
int main()
{
//	freopen("data.in","r",stdin);
//	freopen("myans.out","w",stdout);
	mem(nxt0,-1);
	scanf("%s",s+1);
	n=strlen(s+1);
	FOR(i,1,n) a[i]=(s[i]=='1');
	if (pan1()) {write(0);putchar('\n');exit(0);}
	pos1=-1;
	For(i,n,1)
	{
		nxt1[i]=pos1;
		if (a[i]) pos1=i;
	}
	pos0=-1;
	For(i,n,1)
	{
		nxt0[0][i]=pos0;
		if (!a[i]) pos0=i;
	}
	FOR(j,1,20)
		For(i,n,1) if (nxt0[j-1][i]!=-1) nxt0[j][i]=nxt0[j-1][nxt0[j-1][i]];
	FOR(k,1,(n-1)/2) 
		ans=max(ans,solve(k));
	pan2();
	write(ans);
	putchar('\n');
	return 0;
}

B. 路径长度 赛后代码

#include<bits/stdc++.h>
#define FOR(i,a,b) for (register ll i=(a);i<=(b);i++)
#define For(i,a,b) for (register ll i=(a);i>=(b);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register ll j=f[u];j!=-1;j=nxt[j])
#define pb push_back
using namespace std;
typedef long long ll;
const ll N=2e5+5;
ll n,tag,ans[N],m,q,tmp1,tmp2,tmp3;
ll tot=0,f[N],nxt[N<<1];
vector <ll> vec[N],T;
vector <ll> :: iterator it;
struct E
{
	ll u,v,w;
}e[N<<1];
inline void add(ll u,ll v,ll w)
{
	tot++;
	nxt[tot]=f[u];
	f[u]=tot;
	e[tot]=(E){u,v,w};
	return;
}
inline ll read()
{
	ll x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
inline void write(ll x)
{
	if (x<0) putchar('-'),x=-x;
	if (x>9) write(x/10);
	putchar(x%10+'0');
	return;
}
inline void solve()
{
	vec[1].pb(0);
	FOR(i,2,n)
	{
		T.clear();
		GO(i)
		{
			ll v=e[j].v,w=e[j].w;
			FOR(k,0,(ll)vec[v].size()-1)
				T.pb(w+vec[v][k]);
		}
		sort(T.begin(),T.end());
		FOR(j,0,(ll)T.size()-1)
		{
			while (vec[i].size()>=2&&(10.0*T[j]/11<=vec[i][(ll)vec[i].size()-2])) vec[i].pop_back();
			vec[i].pb(T[j]);
		}
	}
	return;
}
inline void debug()
{
	FOR(i,1,n)
	{
		printf("# %d :\n",i);
		FOR(j,0,(ll)vec[i].size()-1) printf("%d ",vec[i][j]);
		putchar('\n');
	}
	return;
}
int main()
{
//	freopen("data.in","r",stdin);
	mem(f,-1);
	n=read(),m=read(),q=read();
	FOR(i,1,m) tmp1=read(),tmp2=read(),tmp3=read(),add(tmp2,tmp1,tmp3);
	solve();
//	debug();
	while (q--)
	{
		ans[0]++;
		tmp1=read(),tmp2=read();
		it=lower_bound(vec[tmp1].begin(),vec[tmp1].end(),tmp2);
		if (it==vec[tmp1].end()) ans[ans[0]]=0;
		else
		{
			ll val=*it;
			if (10.0*val/11<=tmp2) ans[ans[0]]=1;
			else ans[ans[0]]=0;
		}
	}
	FOR(i,1,ans[0])
	{
		if (ans[i]) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

C. 动态矩阵最短路 赛后代码

#include<bits/stdc++.h>
#define FOR(i,a,b) for (register int i=(a);i<=(b);i++)
#define For(i,a,b) for (register int i=(a);i>=(b);i--)
#define mem(i,j) memset(i,j,sizeof(i))
#define GO(u) for (register int j=f[u];j!=-1;j=nxt[j])
using namespace std;
typedef long long ll;
const int N=1e5+5;
const int inf=1e6;
int n,m,q,ans[3*N],time_now=0,Row[N],Col[N];
int opt,tmp1,tmp2,tmp3,tmp4,tmp5,check;
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f*x;
}
inline void write(int x)
{
	if (x<0) putchar('-'),x=-x;
	if (x>9) write(x/10);
	putchar(x%10+'0');
	return;
}
struct Segment_Tree
{
	int mn[N<<2],mx[N<<2];
	inline void up(int p) {mn[p]=min(mn[p<<1],mn[p<<1|1]);mx[p]=max(mx[p<<1],mx[p<<1|1]);return;}
	inline void bd(int p,int l,int r)
	{
		mn[p]=mx[p]=0;
		if (l==r) {Row[l]=Col[l]=0;return;}
		int ls=p<<1,rs=p<<1|1,mid=(l+r)>>1;
		bd(ls,l,mid);bd(rs,mid+1,r);
		up(p);
		return;
	}
	inline void md(int p,int l,int r,int k,int v)
	{
		if (l==r) {mn[p]=v;mx[p]=v;return;}
		int ls=p<<1,rs=p<<1|1,mid=(l+r)>>1;
		if (k<=mid) md(ls,l,mid,k,v);
		else md(rs,mid+1,r,k,v);
		up(p);
		return;
	}
	inline int qr_min(int p,int l,int r,int L,int R)
	{
		if (L<=l&&r<=R) return mn[p];
		int ls=p<<1,rs=p<<1|1,mid=(l+r)>>1,ret=inf;
		if (L<=mid) ret=min(ret,qr_min(ls,l,mid,L,R));
		if (R>mid) ret=min(ret,qr_min(rs,mid+1,r,L,R));
		if (ret==inf) return -1;
		return ret;
	}
	inline int qr_max(int p,int l,int r,int L,int R)
	{
		if (L<=l&&r<=R) return mx[p];
		int ls=p<<1,rs=p<<1|1,mid=(l+r)>>1,ret=0;
		if (L<=mid) ret=max(ret,qr_max(ls,l,mid,L,R));
		if (R>mid) ret=max(ret,qr_max(rs,mid+1,r,L,R));
		return ret;
	}
	inline int find_left(int lim,int pos,int v)
	{
		int L=1,R=pos,MID,ret=-1;
		while (L<R)
		{
			MID=(L+R+1)>>1;
			if ((check=qr_max(1,1,lim,MID,pos))>=v) L=MID,ret=0;
			else R=MID-1;
		}
		if (qr_max(1,1,m,pos,L)>=v) ret=0;
		if (ret==-1) return ret;
		return L;
	}
	inline int find_right(int lim,int pos,int v)
	{
		int L=pos,R=lim,MID,ret=-1;
		while (L<R)
		{
			MID=(L+R)>>1;
			if ((check=qr_max(1,1,m,pos,MID))>=v) R=MID,ret=0;
			else L=MID+1;
		}
		if ((check=qr_max(1,1,m,pos,L))>=v) ret=0;
		if (ret==-1) return ret;
		return L;
	}
}row,col;
inline int solve(int a,int b,int c,int d,int v)
{
	if (a==c&&b==d) return 0;
	v=time_now-v;//最后一次修改时间大于等于v的位置有效 
	int dis=abs(a-c)+abs(b-d);
	int A=Row[a],B=Col[b],C=Row[c],D=Col[d];
	if (max(A,B)<v||max(C,D)<v) return -1;
	//case 1:拐角型
	if (A>=v&&D>=v) return dis;
	if (B>=v&&C>=v) return dis;
	//case 2:铺满型
	if (a>c) swap(a,c),swap(A,C);
	if (b>d) swap(b,d),swap(B,D);
	if (row.qr_min(1,1,n,a,c)>=v) return dis;
	if (col.qr_min(1,1,m,b,d)>=v) return dis;
	//case 3:"2+1"型
	int tmp,ret=inf;
	if (A>=v&&C>=v)
	{
		if (col.qr_max(1,1,m,b,d)>=v) return dis;
		tmp=col.find_left(n,b,v);
		if (tmp!=-1) ret=min(ret,abs(a-c)+abs(b-tmp)+abs(d-tmp));
		tmp=col.find_right(n,d,v);
		if (tmp!=-1) ret=min(ret,abs(a-c)+abs(b-tmp)+abs(d-tmp));
	}
	if (B>=v&&D>=v)
	{
		if (row.qr_max(1,1,n,a,c)>=v) return dis;
		tmp=row.find_left(m,a,v);
		if (tmp!=-1) ret=min(ret,abs(b-d)+abs(a-tmp)+abs(c-tmp));
		tmp=row.find_right(m,a,v);
		if (tmp!=-1) ret=min(ret,abs(b-d)+abs(a-tmp)+abs(c-tmp));
	}
	if (ret!=inf) return ret;
	return -1;
}
int main()
{
	
	n=read(),m=read(),q=read();
	row.bd(1,1,n);
	col.bd(1,1,m);
	while (q--)
	{
		time_now++;
		opt=read(),tmp1=read();
		if (opt==3) tmp2=read(),tmp3=read(),tmp4=read(),tmp5=read();
		switch (opt)
		{
			case 1:
				Row[tmp1]=time_now;
				row.md(1,1,n,tmp1,time_now);
				break;
			case 2:
				Col[tmp1]=time_now;
				col.md(1,1,m,tmp1,time_now);
				break;
			case 3:
				ans[0]++;
				ans[ans[0]]=solve(tmp1,tmp2,tmp3,tmp4,tmp5);
				break;
		}
	}
	FOR(i,1,ans[0]) write(ans[i]),putchar('\n');
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章