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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章