BZOJ 4569: [Scoi2016]萌萌哒

9 篇文章 0 订阅
4 篇文章 0 订阅

妙啊 我好菜啊

将一个要求用ST表分割成logn个要求,如果把 f[i][j] f[u][v] 在同一个集合,那么 f[i][j1] f[u][v1] f[i+2v1][j1] f[u][u+2v1][v1] 就并到同一个集合,最后只需要计算f[i][0]不同的集合数cnt,则答案为 910cnt1 特判一波n=1就好

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+2,mod=1e9+7;
char B[1<<14],*S=B,*T=B;
#define gc (S==T&&(T=(S=B)+fread(B,1,1<<14,stdin),S==T)?-1:*S++)
inline int read(){
    int x=0,f=1; char ch=gc;
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=gc;}
    while(ch>='0' && ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=gc;}
    return x*f;
}
int f[N][17],F[N*17],b[17],px[N*17],py[N*17],tot;
bool v[N*17];
int fa(int x){return x==F[x]?x:F[x]=fa(F[x]);}
void merge(int x,int y){x=fa(x),y=fa(y),F[x]=y;}
int main(){
    int i,j,n=read(),m=read(); b[0]=1,tot=0;
    if(n==1)return puts("0"),0;
    for(i=1;i<17;++i) b[i]=b[i-1]<<1;
    for(i=1;i<=n;++i)
        for(j=0;j<17;++j)
            if(i+b[j]-1<=n)f[i][j]=++tot,F[tot]=tot,px[tot]=i,py[tot]=j;
            else break;
    for(i=1;i<=m;++i){
        int l1=read(),r1=read(),l2=read(),r2=read();
        for(j=16;~j;--j)
            if(l1+b[j]-1<=r1) merge(f[l1][j],f[l2][j]),l1+=b[j],l2+=b[j];
    }
    for(j=16;j;--j)
        for(i=1;i<=n;++i) if(f[i][j]){
            int u=fa(f[i][j]),x=px[u];
            merge(f[i][j-1],f[x][j-1]);
            merge(f[i+b[j-1]][j-1],f[x+b[j-1]][j-1]);
        }
    int ans=9,c=-1;
    for(i=1;i<=n;++i) if( !v[f[i][0]=fa(f[i][0])] )v[f[i][0]]=1,++c;
    while(c--)ans=1ll*ans*10%mod;
    printf("%d\n",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值