• 2016百度之星资格赛 Problem A(前缀积与求逆元)


      题意:给出一个字符串,每次询问给出x和y要求算出从x到y的每个字符的(ASCII 码值-28)的值的积(mod9973)。

      分析:首先的想法肯定是算出每个位置的前缀积,然后只要F[y]/F[x-1]即可。但是每个前缀积都已经mod9973了,就不能直接这样得出结果了,所以利用求逆元。因为a/b(mod p)p是质数的话,相当于a*inv(b) (mod p),所以只要保存每个位置的前缀积和前缀积的逆元就可以了。

      但是题目有个坑点,如果x和y超出了这次字符串的位置,可以使用上一次数据储存的值而不是0,因为题目给定了x和y是不会超过字符串的长度的,所以每次给出输入数据以后我都memset一遍,导致这个地方WA了好几次。

      同时,这里有个技巧就是,既然逆元是mod9973的,那么只要储存下0到9972的逆元做个预处理即可节省大量的时间。具体见代码:

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 using namespace std;
     5 const int mod = 9973;
     6 int inv(int a,int b) //b是mod-2
     7 {
     8     int ans=1;
     9     while(b)
    10     {
    11         if(b&1) ans=(ans*a)%mod;
    12         b>>=1;
    13         a=a*a%mod;
    14     }
    15     return ans;
    16 }
    17 char s[100000+10];
    18 int num[100000+10];
    19 int p[100000+10];
    20 int res[10000];
    21 int main()
    22 {
    23     int T;
    24     for(int i=1;i<mod;i++) res[i]=inv(i,mod-2);
    25     while(scanf("%d",&T)==1)
    26     {
    27         scanf("%s",s+1);
    28         int len =strlen(s+1);
    29         //memset(num,0,sizeof(num));
    30         //memset(p,0,sizeof(p));
    31         num[0]=p[0]=1;
    32         for(int i=1;i<=len;i++)
    33         {
    34             num[i]=num[i-1]*(s[i]-28)%mod;
    35             p[i]=res[num[i]];
    36         }
    37         while(T--)
    38         {
    39             int x,y;
    40             scanf("%d%d",&x,&y);
    41             printf("%d
    ",num[y]*p[x-1]%mod);
    42         }
    43     }
    44     return 0;
    45 }

    注意红色部分的代码即可。

  • 相关阅读:
    Mysql高级第一天(laojia)
    Mysql初级第三天(wangyun)
    Mysql初级第二天(wangyun)
    Mysql初级第一天(wangyun)
    Spring的源码解析
    JAVA8新特性
    java8
    JMM内存模型
    JAVA并发工具类
    mybatis
  • 原文地址:https://www.cnblogs.com/zzyDS/p/5492894.html
Copyright © 2020-2023  润新知