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
根号分治,设阈值
-
对于
的颜色段。不断进行合并的时间复杂度是 的。 -
对于
的颜色段。可以简单做到 。
总时间复杂度
T2
zzk 模拟赛题的加强版。
dp,
#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
不会。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具