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]=0r[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 前的第一个蓝色为 d2i-x>=d1 && i-2x>=d2枚举 左端点枚举最后一个包含到的红色点一定不能包含下一个红色点设与最后一个包含到的红色点的距离为 s 那么与下一个红色点的距离 >2s那么最多枚举 log 次线段树维护抽象一下上面的条件就是 y-d>=2*(x-d) 2x-2d<=y-d 2x-y<=d*/
T3
不会。