题意就是求(n-1)%n,n很大,O(n)的暴力求法是行不通的。
观察可以发现,如果n是合数,那么1*2*3*4*......*n-1中包含了n的所有质因子,
比如n=9,3和6中各含有一个3.
但是有一个特例,4,只有这个合数不满足此规律。
如果是质数呢?题解是“威尔逊定理”:
在初等数论中,威尔逊定理给出了判定一个自然数是否为素数的充分必要条件。即:当且仅当p为素数时:( p -1 )! ≡ p-1 ( mod p ),但是由于阶乘是呈爆炸增长的,其结论对于实际操作意义不大。——百度百科
比赛的时候估计知道这个的不多,先测试一下n比较小的情况,应该能一眼看出来了,n为质数的时候答案是n-1
n比较大,判断的时候最好用Miller_Rabin素数测试,也可以打出35000以内的素数表来试除,能过。
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
bool isComposite(LL a,LL n)
{
LL i,temp,last;
temp=1;
i=ceil(log(n-1.0)/log(2.0)) - 1;
for(; i>=0; i--)
{
last=temp;
temp=(temp*temp)%n;
if(temp==1 && last!=1 && last!=n-1)
return 1;
if( ((n-1) & (1<<i)) > 0)
temp=(temp*a)%n;
}
return temp==1 ? 0 : 1;
}
//使用固定的质数,速度更快,但准确性比上一版本低
bool Miller_Rabin(LL n)
{
int i;
int s[3]= {2,7,61};
if(n==2)
return 1;
if(n==1 || ((n&1)==0))
return 0;
for(i=0; i<3; i++)
if(isComposite(s[i], n))
return 0;
return 1;
}
void work()
{
int n,ans;
scanf("%d",&n);
if(n==4)
{
printf("2\n");
return ;
}
if(Miller_Rabin(n))
ans=n-1;
else
ans=0;
printf("%d\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
work();
return 0;
}