ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

hdu 3461 Code Lock 题解 (思维,并查集)

2019-06-02 20:51:58  阅读:282  来源: 互联网

标签:hdu Code 传递性 int 题解 cnt 密码 lt 区间


原题链接:
HDU

题意简述

给定nnn,表示密码长度为nnn。
给定mmm和mmm个区间,每个区间是珂以翻转的,即整体+k+k+k之后是相同的密码。注意,z+1=az+1=az+1=a。比如,如果一个长度为222的密码,111到222珂以翻转,那么ab,bc,cd,dezaab,bc,cd,de\cdots zaab,bc,cd,de⋯za都是相同的密码。

问有多少种不同的密码。对109+710^9+7109+7(即100000000710000000071000000007)取模。

数据

输入

多组数据。对于每个数据,
第一行有两个正整数n,m(n&lt;=1e7,m&lt;=1e3)n,m(n&lt;=1e7,m&lt;=1e3)n,m(n<=1e7,m<=1e3),表示区间长度和珂翻转的区间个数。
接下来mmm行每行两个正整数l,rl,rl,r,描述一个珂以翻转的区间[l,r][l,r][l,r]。

输出

对于每个数据,输出答案。

样例

输入
1 1
1 1
2 1
1 2
输出
1
26

思路

我们会发现,答案肯定是26k26^k26k。因为每翻转一个区间,答案都是不断的除262626的。

那么,kkk是多少呢?

开始我们会有这样一个猜测:k=nmk=n-mk=n−m。但是过会我们就被打脸了,而且是被自己打的:看这组数据

4 3
1 2
3 4
1 4

答案应该是26226^2262。珂是按上面那个算法跑出来是26126^1261。再说,不同的区间数应该会有n(n+1)/2n(n+1)/2n(n+1)/2个,拿nnn减去它。。。估计会跑出来个262626的负几次方。。。

那么为什么会出现这种情况呢?原因是有一些区间是没用的。比如说,当我们有了[1,2][1,2][1,2]和[3,4][3,4][3,4]后,[1,4][1,4][1,4]就没用了。那么,如何维护这个关系呢?

找到通用形式:[a,b],[b+1,c][a,b],[b+1,c][a,b],[b+1,c]得出[a,c][a,c][a,c],其中a&lt;=b&lt;ca&lt;=b&lt;ca<=b<c。我们会发现这个式子有点像等式的\red{传递性}传递性,珂是好像有没有,一个是bbb,一个是b+1b+1b+1。怎么办呢?

我们把它弄成\red{前开后闭区间}前开后闭区间不就好了?然后就变成了[a1,b],[b,c][a-1,b],[b,c][a−1,b],[b,c]得出[a1,c][a-1,c][a−1,c]。我们发现,这太具有传递性了。搞个并查集,就过了。

具体的方法:

  1. 一开始设cnt=ncnt=ncnt=n
  2. 每次合并区间(前开后闭)的时候,记得判一下是否已经在同一个集合里。如果不在,那么cnt--cnt−−cnt。
  3. 最后用快速幂求出26cnt%100000000726^{cnt}\%100000000726cnt%1000000007。

代码:

#include<cstdio>
using namespace std;
namespace Flandle_Scarlet
{
    #define ll long long
    #define N 10000001
    #define mod 1000000007
    int n,m;
    ll cnt;
    class DSU//并查集
    {
        public:
            int Father[N];
            void Init()
            {
                for(int i=0;i<=n+5;i++)
                {
                    Father[i]=i;
                }
            }
            int Find(int x)
            {
                return (x==Father[x])?x:(Father[x]=Find(Father[x]));
            }
            void Merge(int x,int y)//懒得写按秩合并了
            {
                int ax=Find(x),ay=Find(y);
                if (ax!=ay)
                {
                    --cnt;
                    Father[ax]=ay;
                }
            }
    }D;
    ll qpow(ll a,ll b,ll m)//快速幂
    {
        ll r=1;
        while(b)
        {
            if (b&1) r=r*a%m;
            a=a*a%m,b>>=1;
        }
        return r;
    }
    void Input()
    {
        cnt=n;
        for(int i=1;i<=m;++i)
        {
            int l,r;scanf("%d%d",&l,&r);
            D.Merge(l-1,r);
            //前开后闭
        }
        printf("%lld\n",qpow(26,cnt,mod));
    }

    void IsMyWife()
    {
        if (0)
        {
            freopen("","r",stdin);
            freopen("","w",stdout);
        }
        while(scanf("%d%d",&n,&m)==2)
        {
            D.Init();
            Input();
        }
    }
    #undef ll //long long
    #undef N //10000001
    #undef mod //1000000007
};
int main()
{
    Flandle_Scarlet::IsMyWife();
    return 0;
}

回到总题解界面

标签:hdu,Code,传递性,int,题解,cnt,密码,lt,区间
来源: https://blog.csdn.net/LightningUZ/article/details/90742625

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有