Loading

P3295 [SCOI2016] 萌萌哒

好题目啊!

看到题目,思考一下发现我们要找出所有不同的位置的个数,假设这个数字为 \(ans\),那么答案就是 \(10^{ans-1}\times 9\)

为什么要减一?因为题目中说这是一个十进制大数,所以第一位不能是0,有 \(9\) 种选择。

按照这个思路,我们可以用并查集来维护,朴素代码如下。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,mod=1e9+7;
int kasumi(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)res=1ll*res*a%mod;
        a=1ll*a*a%mod,b>>=1;
    }
    return res;
}
int n,m,f[N],vis[N],ans;
int find(int x)
{
    if(f[x]==x)return x;
    return f[x]=find(f[x]);
}
void merge(int x,int y)
{
    if(find(x)==find(y))return;
    f[f[x]]=f[y];
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1,l1,r1,l2,r2;i<=m;i++)
    {
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        for(int j=1;j<=r1-l1+1;j++)merge(l1+j-1,l2+j-1);
    }
    for(int i=1;i<=n;i++)ans+=(!vis[find(i)]),vis[f[i]]=1;
    printf("%d",9ll*kasumi(10,ans-1)%mod);
    return 0;
}

但这只能拿到 \(30\) 分,怎么进一步优化呢?

事实上,瓶颈在于每个限制条件,我们都要为对应的每一位一一在并查集中合并,效率很低。

所以可以把\(l1\sim r1\)\(l2\sim r2\) 切成一块块,把每一块分别合并就好了。

因为最终要统计每一位的相同情况,所以分块不太行,就可以采用倍增了。

最后还要把大块上的合并传到小块上面,代码如下。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,mod=1e9+7;
int kasumi(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)res=1ll*res*a%mod;
        a=1ll*a*a%mod,b>>=1;
    }
    return res;
}
int n,m,f[N][25],vis[N],ans;
int find(int x,int s)
{
    if(f[x][s]==x)return x;
    return f[x][s]=find(f[x][s],s);
}
void merge(int x,int y,int s)
{
    if(find(x,s)==find(y,s))return;
    f[f[x][s]][s]=f[y][s];
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)for(int j=0;j<=20;j++)f[i][j]=i;
    for(int i=1,l1,r1,l2,r2;i<=m;i++)
    {
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        for(int j=20;j>=0;j--)if(l1+(1<<j)-1<=r1)merge(l1,l2,j),l1+=(1<<j),l2+=(1<<j);
    }
    for(int j=19;j>0;j--)for(int i=1,p;i+(1<<j)-1<=n;i++)p=find(i,j),merge(i,p,j-1),merge(i+(1<<(j-1)),p+(1<<(j-1)),j-1);;
    for(int i=1;i<=n;i++)ans+=(!vis[find(i,0)]),vis[f[i][0]]=1;
    printf("%d",9ll*kasumi(10,ans-1)%mod);
    return 0;
}
posted @ 2025-07-18 18:04  AvisD  阅读(17)  评论(0)    收藏  举报