zoukankan      html  css  js  c++  java
  • hdu 5685 Problem A (逆元)

    题目

    题意:H(s)=∏i≤len(s)i=1(Si−28) (mod 9973),求一个字符串 子串(a 位到 b 位的)的哈希值。这个公式便是求字符串哈希值的公式,(字符的哈希值 = 字符的ASCII码 - 28),字符串的哈希值等于字符的哈希值的乘积( ∏ 这个就是累乘符号 )。

    化简过后的题意就是求一段序列中的区间乘,由于询问次数比较多,直接求乘会超时

    就比如如下代码:

    #include<stdio.h>
    char s[100010];
    
    int main()
    {
        int T,a,b;
        while(~scanf("%d",&T))
        {
            int ans = 1;
            scanf("%s",s+1);
            while(T--){
                    ans =1;
                scanf("%d%d",&a,&b);
                for(int i=a;i<=b;i++)
                    ans  = ans * (s[i] - 28 ) % 9973;
                     printf("%d
    ",ans);
            }
    
        }
        return 0;
    }
    
    所以用前缀乘的方法,例如:0到b 区间的哈希值,除以 0到a 区间的哈希值,得到的就是 a 到 b 的哈希值。

    若用preMulit[i]表示前i个序列的前缀乘。要求[l,r]区间内的的数字全乘起来,那么用preMulit[r] / preMulit[l-1] 即可,考虑到取模的问题,用到逆元。

    那么我就要问了,为什么考虑到取模的问题,就要用到逆元呢?而且什么是逆元呢?

    (看链接)

    接下来就是解题代码了

    代码一:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const ll maxn=100005;
    const ll mod=9973;
    ll sum[maxn],inv[maxn],re[maxn];
    char s[maxn];
    int main()
    {
        inv[1]=1;
        for(int i=2;i<maxn;++i)
        {
            inv[i]=inv[mod%i]*(mod-mod/i)%mod;
        }
        int n;
        //freopen("shuju.txt","r",stdin);
        while(~scanf("%d",&n))
        {
            scanf("%s",s+1);
            sum[0]=re[0]=1;
            for(int i=1;s[i]!=0;++i)
            {
                sum[i]=(sum[i-1]*(s[i]-28))%mod;
                re[i]=inv[sum[i]];
            }
            for(int i=0;i<n;++i)
            {
                ll a,b;
                scanf("%lld%lld",&a,&b);
                ll tp=re[a-1];
                printf("%I64d
    ",(sum[b]*tp)%mod);
            }
        }
        return 0;
    }


    代码二:(通过extgcd直接求)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const ll maxn=100005;
    const ll mod=9973;
    ll sum[maxn];
    char s[maxn];
    void extgcd(ll a,ll b,ll &x,ll &y)
    {
        if(!b)
        {
            x=1;y=0;
            return;
        }
        extgcd(b,a%b,y,x);
        y-=(a/b)*x;
    }
    ll inv(ll a,ll n)
    {
        ll d,x,y;
        extgcd(a,n,x,y);
        return (x+n)%n;
    }
    int main()
    {
        int n;
        //freopen("shuju.txt","r",stdin);
        while(~scanf("%d",&n))
        {
            scanf("%s",s+1);
            sum[0]=1;
            for(int i=1;s[i]!=0;++i)
            {
                sum[i]=(sum[i-1]*(s[i]-28))%mod;
            }
            for(int i=0;i<n;++i)
            {
                ll a,b;
                scanf("%lld%lld",&a,&b);
                ll tp=inv(sum[a-1],mod);
                printf("%I64d
    ",(sum[b]*tp)%mod);
            }
        }
        return 0;
    }




  • 相关阅读:
    Docker学习-安装,配置,运行
    Docker学习-从无知到有知的学习过程
    学习记录-java基础部分(一)
    对get post等http请求方式的理解
    Mac和window实现双向数据传输
    git pull时 git cannot lock ref XXXXXX (unable to update local ref)错误解决方案
    三年内我的计划和方向
    关于云服务器和云部署的实操(新手级别入门)
    win7蓝屏死机0x0000003B错误蓝屏故障解决
    JAVA代码:生成一个集合,自定义大小,100以内的随机整数
  • 原文地址:https://www.cnblogs.com/qie-wei/p/10160251.html
Copyright © 2011-2022 走看看