题目链接
今天郁闷啊,网络赛在打酱油,就一个题可以贪心可以搞,暴搜一下,TLE,贪心一下WA,直接没心情再去做了,虽然题目描述也有点问题,但是主要还是自己没有状态啊。。。日子还是要继续,明天继续加油!这个题目上午做的,同样也是很郁闷。。。
题目思路:很明显的polya,每隔一个置换的种数是m^gcd(i,n),所以要用到欧拉函数和快速幂模,本来这样准备开始写的,想了想还需要除以n,除法取模啊,找各种资料啊,找到几个关于分数取模的资料,先学习一下。。。然后发现需要扩展欧几里得。。。用扩展欧几里得求逆元,逆元貌似离散里学过(忘了),然后把这个除法就变成乘法了,a*n+b*M = 1扩展欧几里得求出a,取一下正,然后交上发现WA,检查了一下,各个地方都没错啊,找了一下题解 ,原来从0-M-1枚举一下,满足i*n %M = ans % M就可以求出最后结果。。。
知道了算法了,但是离着做对还差很远很远。。。之后我又遇到的问题:
1.欧拉函数模版效率很低。TLE,之后换了一个先筛素数,然后再判断的。
2.在中间很多细节,写的搓了,就TLE,比如不要用i*i <= n而是要先sqrt(n),前者效率低死了。
3.全局变量不要乱用,其实我也不知道是否影响效率。。。这个题我用了全局变量存sqrt(n),就超时了。。。
4.中间溢出,最后枚举i*n会溢出,想想就知道会溢出啊,真SB了,会导致WA,不知错了多少次。。。
每一个都是细节问题,这些都是编码时候的习惯问题,不注意小问题,在遇到很卡时间的题目,这些细节会TLE到死啊。。。
1 #include2 #include 3 #include 4 #include 5 #define M 9937 6 #define ll __int64 7 using namespace std; 8 int num; 9 int o[60001],prim[5001]; 10 int fastmod(int a,int b) 11 { 12 int ans = 1; 13 while(b) 14 { 15 if(b&1) 16 ans = a*ans%M; 17 a = (a%M)*(a%M)%M; 18 b = b >> 1; 19 } 20 return ans; 21 } 22 int euler(int n) 23 { 24 int i,ans = n,m = (int)sqrt(n + 0.5); 25 for(i = 1; i <= num-1&&prim[i] <= m; i ++) 26 { 27 if(n%prim[i] == 0) 28 { 29 ans = ans/prim[i]*(prim[i]-1); 30 while(n%prim[i] == 0) n = n/prim[i]; 31 } 32 } 33 if(n > 1) ans = ans/n*(n-1); 34 return ans%M; 35 } 36 int main() 37 { 38 int n,m,i,j,ans; 39 m = 60000; 40 num = 1; 41 for(i = 2; i <= m; i ++) 42 { 43 if(!o[i]) 44 { 45 prim[num ++] = i; 46 for(j = i+i; j <= m; j += i) 47 { 48 o[j] = 1; 49 } 50 } 51 } 52 while(scanf("%d%d",&n,&m)!=EOF) 53 { 54 ans = 0; 55 j = (int)sqrt(n + 0.5); 56 for(i = 1; i <= j; i ++) 57 { 58 if(n % i == 0) 59 { 60 ans = (ans + euler(n/i)*fastmod(m,i)%M)%M; 61 if(i != n/i) 62 ans = (ans + euler(i)*fastmod(m,n/i)%M)%M; 63 } 64 } 65 for (i = 0; i < M; i++) 66 if ((ll)i*n % M == ans % M)//注意溢出 67 break; 68 printf("%d\n", i); 69 } 70 return 0; 71 }