CSP2024 前集訓:csp-s模擬11

卡布叻_周深發表於2024-10-16

前言

image

T1 掛了,後面幾道賽時都不那麼可做,T2 讀假題了浪費太多時間,T3 沒調出來。

T4 是原,但是整個機房只有一個人當時改了,所以還是沒人寫,因為 T4 是原,還加了個 T5,也不太可做。

T1 玩水

對於一個點 \((i,j)\),若 \(s_{i+1,j}=s_{i,j+1}\) 則稱其為分點,若一個分店後面還有分點或兩個分點相鄰則有解,二維字首和維護即可。

點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1010;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int T,n,m,ans,sum[N][N]; char s[N][N]; bitset<N>spl[N];
int calc(int x1,int y1,int x2,int y2) 
{return x1--,y1--,sum[x2][y2]-sum[x1][y2]-sum[x2][y1]+sum[x1][y1];}
signed main()
{
	freopen("water.in","r",stdin),freopen("water.out","w",stdout);
	for(read(T);T;T--,ans=0,memset(sum,0,sizeof(sum)))
	{
		read(n,m); for(int i=1;i<=n;i++) spl[i].reset();
		for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
			for(s[i][j]=getchar_unlocked();s[i][j]<'a'||s[i][j]>'z';s[i][j]=getchar_unlocked());
		for(int i=1;i<=n-1;i++) for(int j=1;j<=m-1;j++)
			if(s[i][j+1]==s[i+1][j]) spl[i][j]=1;
		for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+spl[i][j];
		for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
			if((spl[i][j]&&spl[i][j+1])||(spl[i][j]&&spl[i+1][j])||(spl[i-1][j-1]&&calc(i,j,n,m)))
			{ans=1; break;}
		write(ans),puts("");
	}
}

T2 AVL 樹

中序遍歷最小等價於前序遍歷最小,因為一個點選了他的父親必選。

那麼貪心,若當前點為其父親的左二子,則計算出其右兒子最少需要多少節點,若計算出的 \(\le k\) 就保留當前點即可。

具體實現挺屎的不想說了,統計最小最大深度,找一下規律維護。

點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=5e5+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,rt,sum,f[30],h[N],fa[N],ls[N],rs[N],dep[N],lim[N],used[N]; bitset<N>ans;
void dfs(int x)
{
	if(!x) return ; h[x]=dep[x]=dep[fa[x]]+1;
	dfs(ls[x]),dfs(rs[x]),h[x]=max({h[x],h[ls[x]],h[rs[x]]});
}
bool check(int x)
{
	sum=lim[0]=0; for(int i=x;i;sum+=!ans[i],i=fa[i]) if(ls[fa[i]]==i)
		sum+=f[max({used[fa[i]]-1,dep[x]-1,lim[rs[fa[i]]]})-dep[fa[i]]];
	return sum<=m;
}
void insert(int x)
{
	used[x]=max(used[x],dep[x]); for(int i=x,tmp;i;i=fa[i])
	{
		m-=!ans[i],ans.set(i),used[fa[i]]=max(used[fa[i]],dep[x]);
		if(ls[fa[i]]==i&&(tmp=rs[fa[i]])) lim[tmp]=max(lim[tmp],used[fa[i]]-1);
	}
}
void solve(int x)
{
	if(!x) return ; if(check(x)) insert(x);
	if(!ls[x]||!rs[x]) lim[ls[x]+rs[x]]=max(lim[ls[x]+rs[x]],lim[x]);
	else if(h[ls[x]]>=lim[x])
		lim[ls[x]]=max(lim[ls[x]],lim[x]),lim[rs[x]]=max(lim[rs[x]],lim[x]-1);
	else lim[ls[x]]=max(lim[ls[x]],lim[x]-1),lim[rs[x]]=max(lim[rs[x]],lim[x]);
	solve(ls[x]),solve(rs[x]);
}
signed main()
{
	freopen("avl.in","r",stdin),freopen("avl.out","w",stdout);
	read(n,m); for(int i=1;i<=n;i++) 
		read(fa[i]),fa[i]==-1?fa[rt=i]=0:(i<fa[i]?ls[fa[i]]=i:rs[fa[i]]=i);
	dfs(rt); f[1]=1; for(int i=2;i<=h[rt];i++) f[i]=f[i-1]+f[i-2]+1;
	solve(rt); for(int i=1;i<=n;i++) write(ans[i]);
}

T3 暴雨

水到處流很煩,考慮用一個最高的土地將兩邊分開,這樣只會往一遍流了,這樣列舉這個最高的土地已經 \(O(k)\) 了。

然後直接 DP 轉移,\(f_{i,j,k,0/1}\) 表示到了第 \(i\) 個土地、最大值位置為 \(j\)、鏟了 \(k\) 塊、奇偶性時的方案數,直接轉移即可,考慮鏟 \(k\) 次做多產生 \(k+1\) 個最大值,由此一次 DP 複雜度為 \(O(nk^2)\)

兩遍正序(倒序)各跑一遍合併即可,

細節上,發現 \(j\) 時間是 \(O(k)\),但空間開了 \(O(n)\) (因為這樣好寫)會炸,所以 \(i\) 這一維滾一下即可;同時列舉過的最大值視為已經剷掉,不能再鏟。

點選檢視程式碼
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define mkp make_pair
#define se second
using namespace std;
const int N=25010,M=30,P=1e9+7;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,ans,a[N],id[N],mx[N][M],cnt1[M][2],cnt2[M][2],f[2][N][M][2];
set<pair<int,int> >s;
void dp(int len,int maxx)
{
	reverse(a+1,a+1+n),s.clear();
	memset(f,0,sizeof(f)),f[0][0][0][0]=f[1][1][0][0]=1,f[1][0][1][0]=!!a[1];
	for(int i=1,j;i<=len;mx[i][++j]=0,i++)
	{
		for(s.insert(mkp(a[i],i)),j=0;s.size()>maxx+2;s.erase(s.begin()));
		for(auto it=s.begin();it!=s.end();it++) mx[i][++j]=it->se;
	}
	for(int i=2,x=0,y=1;i<=len;i++,x^=1,y^=1)
	{
		memset(f[x][i],0,sizeof(f[x][i])); for(int j=1,h;j<=maxx+2&&mx[i][j-1];j++)
		{
			if((h=mx[i][j])==i) continue; bool tmp; memset(f[x][h],0,sizeof(f[x][h]));
			for(int k=0;k<=min(i,maxx);k++)
			{
				if(a[i]>=a[h]) (f[x][i][k][0]+=f[y][h][k][0])%=P,(f[x][i][k][1]+=f[y][h][k][1])%=P;
				else f[x][h][k][0]=f[y][h][k][tmp=(a[h]-a[i])&1],f[x][h][k][1]=f[y][h][k][!tmp];
				if(k>0&&a[i]) (f[x][h][k][0]+=f[y][h][k-1][tmp=a[h]&1])%=P,(f[x][h][k][1]+=f[y][h][k-1][!tmp])%=P;
			}
		}
	}
}
signed main()
{
	freopen("rain.in","r",stdin),freopen("rain.out","w",stdout);
	read(n,m); for(int i=1;i<=n;i++) read(a[i]),id[i]=i,mx[i][0]=-1; mx[0][0]=-1;
	sort(id+1,id+1+n,[](int x,int y){return a[x]>a[y];}); reverse(a+1,a+1+n);
	for(int o=m,now;~o;a[n-now+1]=0,o--)
	{
		now=id[m-o+1],memset(cnt1,0,sizeof(cnt1)),memset(cnt2,0,sizeof(cnt2));
		dp(now-1,min(now-1,o));
		for(int i=0;i<=min(now-1,o);i++) 
			for(int j=1;j<=min(now-1,o)+2&&mx[now-1][j-1];j++)
			{
				(cnt1[i][0]+=f[(now-1)&1][mx[now-1][j]][i][0])%=P;
				(cnt1[i][1]+=f[(now-1)&1][mx[now-1][j]][i][1])%=P;
			}
		dp(n-now,min(n-now,o));
		for(int i=0;i<=min(n-now,o);i++) 
			for(int j=1;j<=min(n-now,o)+2&&mx[n-now][j-1];j++)
			{
				(cnt2[i][0]+=f[(n-now)&1][mx[n-now][j]][i][0])%=P;
				(cnt2[i][1]+=f[(n-now)&1][mx[n-now][j]][i][1])%=P;
			}
		for(int i=0;i<=min(now-1,o);i++) (ans+=(1ll*cnt1[i][0]*cnt2[o-i][0]%P+1ll*cnt1[i][1]*cnt2[o-i][1]%P)%P)%=P;
	}
	write(ans);
}

T4 置換

抽象題,看 Pursuing_OIer 的博吧。

T5 傳統題

懶得改,咕了咕了。

相關文章