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=n

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

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

总时间复杂度 O(nnlogn)

T2

zzk 模拟赛题的加强版。

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

#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 @   BYR_KKK  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示