密码锁(并查集+快速幂 C++)

该博客介绍了如何解决一种圆筒形密码锁的问题,其中涉及并查集和快速幂算法的应用。题目要求计算在特定操作区间下,密码锁可能的不同状态数量。通过合并操作区间并计算26的(n-合并次数)次方取模得到答案。博主强调了在处理大数据时的读入优化和快速幂计算的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

密码锁
总时间限制: 5000ms 内存限制: 524288kB
描述
世界上有一种圆筒形密码锁,这种锁有n位,每一位是a-z中的任意一个字母,这种锁一共有m个可操作的区间,对于每个区间都可以整体向上转动(可以转动多次)。比如abc向上转一下就是bcd,zab向上转一下就是abc(z向上转就是a)。你可以同时转动每个区间内的密码锁,能够通过转动使之一样的密码锁为同一种密码,问你这个密码锁总共有多少种不同的密码。
(如可以操作2-4这个区间,那么ABBB和AAAA就是同一个密码。)
输入
输入有一系列测试样例,每个测试样例包含两个整数N(1<=N<=100000000)和M(0<=M<=1000000),分别代表圆筒形密码锁的长度和可操作的区间数量。
接下来M行。每行包含两个整数L和R(1<=L<=R<=N),表示一个可操作的区间。
输出
输出不同的密码数,答案对1000000007取模。
样例输入

1 1
1 1
2 1
1 2

样例输出

1
26

思路点拔:首先,我们走一走样例,第一个就不看了,那么第二个为什么是26种呢?我们可以这么想:首先确定一个区间,然后我们就去算另一个区间可取的情况有多少种,所以26就是这么来的,所以,本题就是用并查集去对输入的两个数作为等价类去进行合并,然后,答案就是26的(n-合并次数)次方,所以,代码应该很明确了,就是要注意:由于本题的数据非常大,所以我们需要进行读入优化,否则会超时,求26的幂就是需要用一个二分思想的快速幂来进行计算,否则也会超时,最后模一下就完事了~,上代码!!!

#include<cstdio>
#include<iostream>
using namespace std;
int tot,n,m;
int mo=1000000007; //模数
long long qkpow(int n)  //快速幂
{
    long long i=1,ans=26;
    while(n>0)
    {
        if(n%2==1) //用二分的思想进行快速计算
        {
            i*=ans;
            i%=mo; //每次算完就要取模
        }
        ans*=ans;
        ans%=mo;
        n/=2; //二分
    }
    return i; //返回结果
}
int fa[200000005]; //定义fa数组存储每个节点的父亲节点
void makeSet(int n) //初始化
{
    for(int i=1;i<=n;i++) 
        fa[i]=i;    
}
int find(int n)//寻找根节点
{
    if(n!=fa[n]) //用递归思求根节点
        fa[n]=find(fa[n]);
    return fa[n]; 
} 
void unionSet(int a,int b) //合并
{
    int x=find(a),y=find(b); //记录两个数的根节点
    if(x!=y) //如果根节点不相等
    {
        fa[x]=y; //合并
        tot++; //统计合并次数
    }
}
bool read(int &x) //读入优化(在本题,读入优化比scanf快200多毫秒)
{
    int f=1;
    x=0;
    char s=getchar();
    while(s<'0'||s>'9') //如果输入的东西不是数字
    {
        if(s=='-') //如果是负的
        f=-1; //f就等于-1
        s=getchar(); //继续读入(getchar()比scanf快得多)
    }
    while(s>='0'&&s<='9') //如果是数字
    {
        x=x*10+s-'0'; //继续读入
        s=getchar();
    }
    x*=f; 
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF) //无限输入
    {
        tot=0; //初始时合并次数为0
        makeSet(n);//初始化
        int a,b;
        for(int i=1;i<=m;i++) //输入
        {
            read(a);
            read(b);
            unionSet(a-1,b); //合并
        }   
        printf("%lld\n",qkpow(n-tot)%mo); //输出结果
    }
    return 0;//结束了
}
//思路不难,但是极易超时(我错了45次 >_<),所以一定要注意,因为时间卡得很紧
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值