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 }

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

原文地址:https://www.cnblogs.com/zzyDS/p/5492894.html