码迷,mamicode.com
首页 > 其他好文 > 详细

codeforces 487C Prefix Product Sequence (模逆元+构造)

时间:2015-04-03 00:03:51      阅读:196      评论:0      收藏:0      [点我收藏+]

标签:

转自http://blog.csdn.net/houserabbit/article/details/41513745

题解写的真棒。。

题目链接:http://codeforces.com/problemset/problem/487/C

 

题目大意:构造一个1~n的排列  使得n个前缀积对n取余是一个0~n-1的排列

 

题目分析:好题,首先我们通过简单的分析可以得到n肯定是最后一个数,因为如果n在前面,前缀积肯定不止1个是n的倍数,也就是说对n取模至少有两个0,显然不满足排列,也就是说取模得到排列最后一个数是0,再来考虑前n-1个数,如果就是1 2 3 4...n-1是不是满足条件呢,显然第一个数就让它是1,是始终正确的,我们已经构造出来两个数了再来看中间的,对于一组序列a1 a2 a3 a4 ... an-1,a1=1,如果a2对n取完模要前缀积及a1*a2*a3对n取模的值与a1*a2的不同,我们不妨在a3中把a2对前缀积的影响消除,后面以此类推,这时就要用到模逆元的概念。

对于正整数技术分享技术分享,如果有技术分享,那么把这个同余方程中技术分享的最小正整数解叫做技术分享技术分享的逆元。如果技术分享为素数,那么还可以根据费马小定理得到逆元为技术分享。推导如下:技术分享

回到本题,我们可以构造ai=(i+1)*inv[i],(inv[i]表示i的模逆元)

这样得到的前缀积a1a2a3...an-1=1*2*inv[1]*3*inv[2]*...*n*inv[n-1]因为inv[2]*2≡1(mod n)相当于前面说的消除了a2对a3的影响进一步分析,如果n是合数,则其必能表示成x*y,这里x,y是除了1和n的其他因子,因此对于前缀积(n-1)!必然能被n整除,这里有个特例4,4可以构造出1 3 2 4,原因很简单,因为4不算最后一项的前缀积为2*3显然6不能被4整除,但是比4大的最小的合数为6,6就不满足了,因为5!=2*3*4*5显然是6的倍数,当n不断扩大的时候,因子越来越多则更加能够被n整除,所以我们得到除了4以外的其他合数都无法构造出这样的序列,接下来就是怎样求模逆元的问题。

根据上面的结论了,可以用费马小定理通过快速幂取模求解模逆元,不过还有更简便的递推式

inv[i]= (n-n/i)*inv[n%i]%n,初始值inv[1]=1这个递推式的推导如下

a=n/i

b=n%i  =>

a*i+b≡0(mod n) (整除部分+余数部分就等于n)  =>

-a*i≡b(mod n) (两边同除b*i)   =>

-a*inv[b]≡inv[i](mod n) (将a,b替换)  =>

-(n/i)*inv[n%i]≡inv[i](mod n) (将左边变为大于0的数,直接加上n即可,因为这时nmodn=0)  =>

(n-n/i)*inv[n%i]≡inv[i](mod n)  =>

inv[i] = (n-n/i)*inv[n%i]%n

下面给出两种解法:

1.递推式:

技术分享
 1 #include <cstdio>
 2 #include <cmath>
 3 #define ll long long
 4 int const MAX = 1e5 + 10;
 5 ll inv[MAX];
 6 int n;
 7 
 8 bool isprime(int x)
 9 {
10     if(x == 1)
11         return false;
12     if(x == 2)
13         return true;
14     if(x % 2 == 0)
15         return false;
16     for(int i = 3; i <= sqrt(n); i += 2) 
17         if(n % i == 0) 
18             return false;
19     return true;
20 }
21 
22 int main() 
23 {
24     scanf("%d", &n);
25     if(n == 4) 
26     {  
27         printf("YES\n1\n3\n2\n4\n");  
28         return 0;  
29     }  
30     else if(n == 1)
31     {
32         printf("YES\n1\n");
33         return 0;
34     }
35     else if(!isprime(n))
36     {
37         printf("NO\n");
38         return 0;
39     }
40     printf("YES\n1\n");
41     inv[1] = 1;
42     for(int i = 2; i < n; i++) 
43     {
44         inv[i] = (n - n / i) * inv[n % i] % n;
45         printf("%lld\n", ((ll) i * inv[i - 1] % n));
46     }
47     printf("%d\n", n);
48 }
代码君

2.费马小定理+快速幂取模 (速度是第1种解法的20倍)

技术分享
 1 #include <cstdio>
 2 #include <cmath>
 3 #define ll long long
 4 int const MAX = 1e5 + 10;
 5 ll inv[MAX];
 6 int n;
 7 
 8 bool isprime(int x)
 9 {
10     if(x == 1)
11         return false;
12     if(x == 2)
13         return true;
14     if(x % 2 == 0)
15         return false;
16     for(int i = 3; i <= sqrt(n); i += 2) 
17         if(n % i == 0) 
18             return false;
19     return true;
20 }
21 
22 ll multi(ll a, ll b)  
23 {  
24     ll ans = 0;  
25     a %= n;  
26     while(b)  
27     {  
28         if(b & 1)  
29         {  
30             ans = (ans + a) % n;  
31             b--;  
32         }  
33         b >>= 1;  
34         a = (a + a) % n;  
35     }  
36     return ans;  
37 } 
38 
39 ll quick_mod(ll a, ll b)  
40 {  
41     ll ans = 1;  
42     a %= n;  
43     while(b)  
44     {  
45         if(b & 1)  
46         {  
47             ans = multi(ans,a);  
48             b--;  
49         }  
50         b >>= 1;  
51         a = multi(a,a);  
52     }  
53     return ans;  
54 }  
55 
56 int main() 
57 {
58     scanf("%d", &n);
59     if(n == 4) 
60     {  
61         printf("YES\n1\n3\n2\n4\n");  
62         return 0;  
63     }  
64     else if(n == 1)
65     {
66         printf("YES\n1\n");
67         return 0;
68     }
69     else if(!isprime(n))
70     {
71         printf("NO\n");
72         return 0;
73     }
74     printf("YES\n1\n");
75     for(int i = 2; i < n; i++) 
76         printf("%lld\n", i * quick_mod(i - 1, n - 2) % n);
77     printf("%d\n", n);
78 }
View Code

 

codeforces 487C Prefix Product Sequence (模逆元+构造)

标签:

原文地址:http://www.cnblogs.com/usedrosee/p/4388757.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!