usaco24DEC

Sliver

T1

感受一下,一定是选一段前缀加后缀。

T2

P1250。

T3

正着做不好做,但是倒着做很好用并查集维护。

#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define debug(...) fprintf(stderr,##__VA_ARGS__)

template<typename T>
void read(T &x){
	x=0;
	int f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
	x*=f;
}

std::stack<char>st;
template<typename T>
void print(T x){
	if(x==0) putchar('0');
	if(x<0) putchar('-'),x=-x;
	while(st.size()) st.pop();
	while(x) st.push((char)('0'+x%10)),x/=10;
	while(st.size()) putchar(st.top()),st.pop();
}

template<typename T>
void printsp(T x){
	print(x),putchar(' ');
}

template<typename T>
void println(T x){
	print(x),putchar('\n');
}

template<typename T,typename I>
void chkmin(T &a,I b){
	a=std::min(a,b);
}

template<typename T,typename I>
void chkmax(T &a,I b){
	a=std::max(a,b);
}

bool Mbe;

const int inf=1e18,MOD1=998244353,MOD2=1e9+7;

const int maxn=1e3+10,maxq=2e5+10;

int n,qq;

int to[maxn],num[maxn],sz[maxn],r[maxq],c[maxq];

char t[maxq],a[maxn][maxn];

bool imp[maxn][maxn];

int go(int p){
	if(to[p]==p) return p;
	return to[p]=go(to[p]);
}

int dx[]={0,1,-1,0,0},dy[]={0,0,0,1,-1};

bool Men;

signed main(){
	debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
	std::cin>>n>>qq;
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]='?';
	for(int i=1;i<=qq;i++) std::cin>>r[i]>>c[i]>>t[i],a[r[i]][c[i]]=t[i];
	for(int i=1;i<=n;i++){
		if(a[1][i]=='U'||a[1][i]=='?') imp[1][i]=1;
		if(a[n][i]=='D'||a[n][i]=='?') imp[n][i]=1;
		if(a[i][1]=='L'||a[i][1]=='?') imp[i][1]=1;
		if(a[i][n]=='R'||a[i][n]=='?') imp[i][n]=1;
	}
	std::queue<std::pair<int,int> >q;
	int ans=0;
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(imp[i][j]) ans++,q.push({i,j});
	while(q.size()){
		int x=q.front().fi,y=q.front().se;
		q.pop();
		// debug("x=%lld y=%lld\n",x,y);
		for(int i=1;i<=4;i++){
			int nx=x+dx[i],ny=y+dy[i];
			if(nx<1||ny<1||nx>n||ny>n) continue;
			if(imp[nx][ny]) continue;
			if(i==1){
				if(a[nx][ny]=='?'||a[nx][ny]=='U') imp[nx][ny]=1;
			}
			if(i==2){
				if(a[nx][ny]=='?'||a[nx][ny]=='D') imp[nx][ny]=1;
			}
			if(i==3){
				if(a[nx][ny]=='?'||a[nx][ny]=='L') imp[nx][ny]=1;
			}
			if(i==4){
				if(a[nx][ny]=='?'||a[nx][ny]=='R') imp[nx][ny]=1;
			}
			if(imp[nx][ny]) q.push({nx,ny}),ans++;
		}
	}
	// debug("ans=%lld\n",ans);
	std::vector<int>vec;
	vec.push_back(n*n-ans);
	for(int i=qq;i>1;i--){
		a[r[i]][c[i]]='?';
		if(imp[r[i]][c[i]]){
			vec.push_back(n*n-ans);
			continue;
		}
		for(int j=1;j<=4;j++){
			int nx=r[i]+dx[j],ny=c[i]+dy[j];
			if(nx<1||nx>n||ny<1||ny>n){
				imp[r[i]][c[i]]=1;
				ans++;
				break;
			}
			if(!imp[nx][ny]) continue;
			imp[r[i]][c[i]]=1;
			ans++;;
			break;
		}
		if(!imp[r[i]][c[i]]){
			vec.push_back(n*n-ans);
			continue;
		}
		q.push({r[i],c[i]});
		while(q.size()){
			int x=q.front().fi,y=q.front().se;
			q.pop();
			// debug("i=%lld x%llld y=%lld\n",i,x,y);
			for(int i=1;i<=4;i++){
				int nx=x+dx[i],ny=y+dy[i];
				if(nx<1||ny<1||nx>n||ny>n) continue;
				if(imp[nx][ny]) continue;
				if(i==1){
					if(a[nx][ny]=='?'||a[nx][ny]=='U') imp[nx][ny]=1;
				}
				if(i==2){
					if(a[nx][ny]=='?'||a[nx][ny]=='D') imp[nx][ny]=1;
				}
				if(i==3){
					if(a[nx][ny]=='?'||a[nx][ny]=='L') imp[nx][ny]=1;
				}
				if(i==4){
					if(a[nx][ny]=='?'||a[nx][ny]=='R') imp[nx][ny]=1;
				}
				if(imp[nx][ny]) q.push({nx,ny}),ans++;
			}
		}
		vec.push_back(n*n-ans);
	}
	std::reverse(vec.begin(),vec.end());
	for(int i:vec) println(i);
	debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}

Gold

T1

根号分治,设阈值 \(B=\sqrt{n}\)

  • 对于 \(\le B\) 的颜色段。不断进行合并的时间复杂度是 \(O(B^2)\) 的。

  • 对于 \(> B\) 的颜色段。可以简单做到 \(O(n\log n)\)

总时间复杂度 \(O(n\sqrt{n}\log n)\)

T2

zzk 模拟赛题的加强版。

dp,\(f_{i}\) 代表考虑 \(1\sim i\) 中,符合最后形态的可能序列有多少。转移是一个非常困难的势能和线段树维护,先不写了。

#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define debug(...) fprintf(stderr,##__VA_ARGS__)

template<typename T>
void read(T &x){
	x=0;
	int f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
	x*=f;
}

std::stack<char>st;
template<typename T>
void print(T x){
	if(x==0) putchar('0');
	if(x<0) putchar('-'),x=-x;
	while(st.size()) st.pop();
	while(x) st.push((char)('0'+x%10)),x/=10;
	while(st.size()) putchar(st.top()),st.pop();
}

template<typename T>
void printsp(T x){
	print(x),putchar(' ');
}

template<typename T>
void println(T x){
	print(x),putchar('\n');
}

template<typename T,typename I>
void chkmin(T &a,I b){
	a=std::min(a,b);
}

template<typename T,typename I>
void chkmax(T &a,I b){
	a=std::max(a,b);
}

bool Mbe;

const int inf=1e18,MOD1=998244353,MOD2=1e9+7;

namespace Tp_SegTree{
/*
clear,push_up,build,push_down,add,update,query_sum,query_mx,query_mi
example:Tp_SegTree::SegTree<(int)size,(int)mod> Name;
		Name.clear(),Name.build(1,n)
*/
	template<int maxn,int mod>
	struct SegTree{
		int tot;
		int l[maxn*2],r[maxn*2],ls[maxn*2],rs[maxn*2],mx[maxn*2],mi[maxn*2],sum[maxn*2],lz[maxn*2];
		SegTree() :tot(){}
		void clear(){
			tot=0;
		}
		void add(int &a,int b){
			a+=b;
			if(a>=mod) a-=mod;
		}
		void push_up(int p){
			sum[p]=(sum[ls[p]]+sum[rs[p]])%mod;
			mx[p]=std::max(mx[ls[p]],mx[rs[p]]);
			mi[p]=std::min(mi[ls[p]],mi[rs[p]]);
		}
		int build(int L,int R){
			int p=++tot;
			l[p]=L,r[p]=R;
			lz[p]=0;
			if(L==R) return sum[p]=0,mx[p]=-inf,mi[p]=inf,p;
			int mid=(L+R)>>1;
			ls[p]=build(L,mid),rs[p]=build(mid+1,R);
			push_up(p);
			return p;
		}
		void push_down(int p){
			if(lz[p]==0) return ;
			add(mi[ls[p]],lz[p]),add(mx[ls[p]],lz[p]),add(sum[ls[p]],(r[ls[p]]-l[ls[p]]+1)*lz[p]%mod);
			add(mi[rs[p]],lz[p]),add(mx[rs[p]],lz[p]),add(sum[rs[p]],(r[rs[p]]-l[rs[p]]+1)*lz[p]%mod);
			add(lz[ls[p]],lz[p]),add(lz[rs[p]],lz[p]);
			lz[p]=0;
		}
		void add(int p,int L,int R,int x){
			if(l[p]>=L&&r[p]<=R){
				add(sum[p],(r[p]-l[p]+1)*x%mod);
				add(mx[p],x),add(mi[p],x),add(lz[p],x);
				return ;
			}
			push_down(p);
			int mid=(l[p]+r[p])>>1;
			if(mid>=L) add(ls[p],L,R,x);
			if(R>mid) add(rs[p],L,R,x);
			push_up(p);
			return ;
		}
		void update(int p,int k,int x){
			if(l[p]==r[p]){
				sum[p]=mx[p]=mi[p]=x;
				return ;
			}
			push_down(p);
			int mid=(l[p]+r[p])>>1;
			if(mid>=k) update(ls[p],k,x);
			else update(rs[p],k,x);
			push_up(p);
			return ;
		}
		int query_sum(int p,int L,int R){
			if(l[p]>=L&&r[p]<=R) return sum[p];
			push_down(p);
			int mid=(l[p]+r[p])>>1,res=0;
			if(mid>=L) add(res,query_sum(ls[p],L,R));
			if(R>mid) add(res,query_sum(rs[p],L,R));
			return res;
		}
		int query_mx(int p,int L,int R){
			if(l[p]>=L&&r[p]<=R) return mx[p];
			push_down(p);
			int mid=(l[p]+r[p])>>1,res=-inf;
			if(mid>=L) chkmax(res,query_mx(ls[p],L,R));
			if(R>mid) chkmax(res,query_mx(rs[p],L,R));
			return res;
		}
		int query_mi(int p,int L,int R){
			if(l[p]>=L&&r[p]<=R) return mi[p];
			push_down(p);
			int mid=(l[p]+r[p])>>1,res=inf;
			if(mid>=L) chkmin(res,query_mi(ls[p],L,R));
			if(R>mid) chkmin(res,query_mi(rs[p],L,R));
			return res;
		}
	};
}

const int maxn=5e5+10;

Tp_SegTree::SegTree<maxn,MOD2>ds[2];

int n;

int a[maxn],f[maxn],nr[maxn],nb[maxn],s[maxn],c[maxn],g[maxn],w[maxn];

void add(int &x,int y){
	x+=y;
	if(x>=MOD2) x-=MOD2;
}

void work(){
	int s1=0,s2=0;
	w[0]=1;
	s2=1;
	for(int i=1;i<=n;i++){
		add(w[i],w[i-1]);
		if(i&1) add(w[i],s1);
		else add(w[i],s2);
		if(i&1) add(s1,w[i]);
		else add(s2,w[i]);
	}
}

bool Men;

signed main(){
	debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
	std::cin>>n;
	std::string ss;
	std::cin>>ss;
	for(int i=1;i<=n;i++){
		if(ss[i-1]=='X') a[i]=0;
		else if(ss[i-1]=='R') a[i]=1;
		else a[i]=2;
	}
	nb[n+1]=nr[n+1]=n+1;
	for(int i=n;i>=1;i--){
		nb[i]=nb[i+1],nr[i]=nr[i+1];
		if(a[i]==2) nb[i]=i;
		if(a[i]==1) nr[i]=i;
	}
	g[0]=0;
	for(int i=1;i<=n;i++){
		g[i]=g[i-1];
		if(a[i]!=0) g[i]=i;
	}
	int cnt=0;
	for(int i=1;i<=n;i++) if(a[i]==1) c[++cnt]=i;
	s[0]=1;
	std::priority_queue<std::pair<int,int> >pq;
	c[++cnt]=n+1;
	for(int i=1;i<cnt;i++) pq.push({2*c[i]-c[i+1],i});
	std::set<std::pair<int,int> >vec;
	while(pq.size()){
		vec.insert(pq.top());
		pq.pop();
	}
	for(int i=0;i<2;i++) ds[i].clear(),ds[i].build(1,n);
	// debug("s=%lld\n",s[0]);
	for(int i=1;i<=n;i++){
		int tot=s[i-1];
		// debug("i=%lld g=%lld s=%lld\n",i,g[i],s[0]);
		if(a[i-1]==1){
			f[i]=ds[i%2].query_sum(1,i,i);
			// debug("i=%lld f=%lld\n",i,f[i]);
			s[i]=s[i-1]+f[i];
			s[i]%=MOD2;
			continue;
		}
		if(a[g[i-1]]==1) tot-=s[g[i-1]];
		else if(g[i-1]!=0)tot-=s[g[i-1]-1];
		tot%=MOD2,tot+=MOD2,tot%=MOD2;
		// debug("i=%lld tot=%lld\n",i,tot);
		std::vector<pii>er;
		for(pii p:vec){
			int d=c[p.se];
			if(d<i){
				er.push_back(p);
				continue;
			}
			if(p.fi>i) break;
			int dd=c[p.se+1];
			int h=d-i+1;
			// debug("i=%lld d=%lld\n",i,d);
			int lim;
			if((dd-i+1)%2==0) lim=i+(dd-i+1)/2-2;
			else lim=i+(dd-i+1)/2-1;
			int down=d;
			int clim;
			if((n+1-i+1)%2==0) clim=i+(n+1-i+1)/2-2;
			else clim=i+(n+1-i+1)/2-1;
			chkmin(lim,nb[i]-1);
			chkmin(lim,clim);
			// debug("down=%lld lim=%lld clim=%lld\n",down,lim,clim);
			if(lim<down) continue;
			down=i+2*(down-i+1)-1;
			lim=i+2*(lim-i+1)-1;
			// debug("down=%lld lim=%lld\n",down,lim);
			ds[((i%2)^1)].add(1,down,lim,tot);
		}
		for(pii p:er) vec.erase(p);
		if(a[i]!=1){
			int down=i,lim,dd=nr[i+1];
			if((dd-i+1)%2==0) lim=i+(dd-i+1)/2-2;
			else lim=i+(dd-i+1)/2-1;
			int clim;
			if((n+1-i+1)%2==0) clim=i+(n+1-i+1)/2-2;
			else clim=i+(n+1-i+1)/2-1;
			chkmin(lim,nb[i]-1);
			chkmin(lim,clim);
			// debug("i=%lld down=%lld lim=%lld\n",i,down,lim);
			if(down<=lim){
				down=i+2*(down-i+1)-1;
				lim=i+2*(lim-i+1)-1;
				ds[((i%2)^1)].add(1,down,lim,tot);
			}
		}
		f[i]=ds[i%2].query_sum(1,i,i);
		// debug("i=%lld f=%lld\n",i,f[i]);
		s[i]=s[i-1]+f[i];
		s[i]%=MOD2;
		// debug("s=%lld\n",s[i]);
	}
	work();
	int ans=0;
	for(int i=1;i<=n;i++){
		if(nr[i]!=n+1||nb[i+1]!=n+1) continue;
		add(ans,f[i]);
	}
	println(ans);
	debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}
/*
r[i]-r[i-x]=0 && b[i-x]-b[i-2x]=0

r[i]=r[i-x] && b[i-x]=b[i-2x]

f[i]=\sum f[j]*(the num of i-2x>=j)

f[i]=\sum [i-2x 合法]*(f[1~i-2x])

令前面第一个红色为 d1 令 d1 前的第一个蓝色为 d2

i-x>=d1 && i-2x>=d2


枚举 左端点

枚举最后一个包含到的红色点

一定不能包含下一个红色点

设与最后一个包含到的红色点的距离为 s 那么与下一个红色点的距离 >2s

那么最多枚举 log 次

线段树维护

抽象一下上面的条件就是 y-d>=2*(x-d) 2x-2d<=y-d 2x-y<=d

*/

T3

不会。

posted @ 2024-12-18 21:39  BYR_KKK  阅读(40)  评论(0)    收藏  举报