• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
ACM s1124yy
守りたいものが 強くさせること
博客园    首页    新随笔    联系   管理     

HDU - 5685 Problem A(逆元)

  这题我第一次想的就是直接模拟,因为我是这样感觉的,输入n是3次方,长度是5次方,加起来才8次方,里面的操作又不复杂,感觉应该能过,然而不如我所料,TLE了,玛德,这是第一次的代码。

#include <bits/stdc++.h>
using namespace std;

const int INF=0x3f3f3f3f;
typedef long long LL;
#define PI(A) printf("%d\n",A)
#define SI(N) scanf("%d",&(N))
#define SII(N,M) scanf("%d%d",&(N),&(M))
#define cle(a,val) memset(a,(val),sizeof(a))
#define rep(i,b) for(int i=0;i<(b);i++)
#define Rep(i,a,b) for(int i=(a);i<=(b);i++)
#define reRep(i,a,b) for(int i=(a);i>=(b);i--)
const double EPS= 1e-9 ;

/*  /////////////////////////     C o d i n g  S p a c e     /////////////////////////  */

const int MAXN= 100000 + 5 ;

char str[MAXN];
int N;


int main()
{
    while(~SI(N))
    {
        int x,y;
        scanf("%s",str);
        while(N--)
        {
            LL ans=1;
            SII(x,y);
            x--,y--;
            for (int i=x;i<=y;i++)
            {
                ans=ans*((int)str[i]-28);
                ans%=9973;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

  之后想了一会,想不通,就查题解了,我看的是这个题解 http://www.cnblogs.com/inmoonlight/p/5512340.html

  看了之后,觉得有几点要注意:

  1.像这样求连乘的,一段区间的东西,一定要先打表,之后在输入查询,否则几乎绝对超时,比如求这题可以换成H(t)/H(s-1),由此可以想到,连加的时候也可以打表,那就是H(t)-H(s-1)

  2.看到大数相除,还取模,那就是逆元了,可以用 exgcd 或 费马小定理求,这里可以写个函数自己判断下m是不是素数,9973 显然是素数,所以就费马小定理。费马小定理,H(n)的逆元为H(n)MOD-2 % MOD,当MOD是素数时。

   之后,理所当然,AC

#include <bits/stdc++.h>
using namespace std;

const int INF=0x3f3f3f3f;
typedef long long LL;
#define PI(A) printf("%d\n",A)
#define SI(N) scanf("%d",&(N))
#define SII(N,M) scanf("%d%d",&(N),&(M))
#define cle(a,val) memset(a,(val),sizeof(a))
#define rep(i,b) for(int i=0;i<(b);i++)
#define Rep(i,a,b) for(int i=(a);i<=(b);i++)
#define reRep(i,a,b) for(int i=(a);i>=(b);i--)
const double EPS= 1e-9 ;

/*  /////////////////////////     C o d i n g  S p a c e     /////////////////////////  */

const int MAXN= 100000 + 5 ;

char str[MAXN];
int h[MAXN];
int N;
int M=9973;

//快速幂模板
LL mod_pow(LL x,LL n,LL mod)
{
    LL res=1;
    while(n>0){
        if (n&1) res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}


int main()
{
    while(~SI(N))
    {
        int x,y;
        scanf("%s",str);
        h[0]=1;
        //注意这是str[i]!='\0' 不是strlen(str) 如果换了 会超时,因为调用函数浪费时间,不信? 你自己试下,就知道了
        for (int i=0;str[i];i++)
        {
            h[i+1]=h[i]*(str[i]-28)%M;
        }
        while(N--)
        {
            SII(x,y);
            printf("%lld\n",h[y]*mod_pow(h[x-1],M-2,M)%M);
        }
    }
    return 0;
}

  做完这题,有个感悟,就是不管什么题,不求速度,只求质量,一定要搞懂,就算一周只看一个题,只要搞懂了,绝对比看100道,一道都没懂好。

  在附赠一个测素数的代码:

 

#include <bits/stdc++.h>
using namespace std;
int N;
int main()
{
    //PS:9973   1e9+7  都是素数
    while(cin>>N)
    {
        bool fl=1;
        for (int i=2;i<=sqrt(N);i++)
        {
            if (N%i==0)
                fl=0;
        }
        puts(fl&&N>1?"yes":"no");
    }

    return 0;
}

 

posted @ 2016-07-15 10:11  s1124yy  阅读(417)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3