bestcoder#51
A题:
求(n-1)!%n。
显然,若n不是素数,n的因子全都存在于1~n-1中,因此(n-1)!%n=0. (n=4时除外)
若n为素数,由威尔逊定理: (n,p互质-> (n-1)!=1(mod p)) ,(n-1)!%n=1。
打表也可以发现规律,注意n=4的时候答案为2的特判。
注意判素数时先筛出素数,在由筛出的素数去判断一个数是否为素数。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); ll n; bool isprime[maxn]; vector<ll> prime; void getP() { MS(isprime,1); isprime[1]=0; REP(i,2,maxn-1){ if(!isprime[i]) continue; REPP(j,i+i,maxn-1,i) isprime[j]=0; } REP(i,1,maxn-1){ if(isprime[i]) prime.PB(i); } } bool isp(ll n) { int sz=SZ(prime); for(ll i=0;i<sz&&prime[i]*prime[i]<=n;i++){ if(n%prime[i]==0) return 0; } return 1; } int main() { // freopen("in.txt","r",stdin); DRI(T); // Init(); getP(); while(T--){ scanf("%I64d",&n); if(isp(n)) printf("%I64d ",n-1); else if(n==4) puts("2"); else puts("0"); } return 0; }
B题:
给出一个置换,求它的循环长度。
分解成循环求长度的最小公倍数。注意由于要取模,lcm不能用a*b/gcd(a,b)=a*b*inv(gcd(a,b))求,因为a和b已经被取模过,gcd(a,b)!=gcd(a%p,b%p)。
lcm的另一种求法:分解质因数。
#include<iostream> #include<stdio.h> #include<string.h> #include<stdlib.h> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #include<memory> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define MS0(a) memset((a),0,sizeof((a))) #define SZ(v) (int)(v).size() #pragma comment(linker, "/STACK:16777216") using namespace std; const int maxn=3000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); const ll MOD=3221225473; int n; int a[maxn]; bool vis[maxn]; #define MAXN 100010 bool isprime[MAXN]; int prime[MAXN],sz; void getPrime() { memset(isprime,1,sizeof(isprime)); isprime[1]=0; REP(i,1,MAXN-1){ if(!isprime[i]) continue; REPP(j,i+i,MAXN-1,i) isprime[j]=0; } sz=0; REP(i,2,MAXN-1){ if(isprime[i]) prime[sz++]=i; } } ll qpow(ll n,ll k,ll p) { ll res=1; while(k){ if(k&1) res=(res*(n%p))%p; n=(n*n)%p; k>>=1; } return res; } ll lcm(ll a,ll b) { ll res=1; a%=MOD,b%=MOD; REP(i,0,sz-1){ int t=prime[i]; if(a%t&&b%t) continue; if(t*t>a&&t*t>b) break; int cntA=0,cntB=0; while(a%t==0) a/=t,cntA++; while(b%t==0) b/=t,cntB++; ll cnt=max(cntA,cntB); res=(res*qpow(t,cnt,MOD))%MOD; } if(a!=1) res=(res*a)%MOD; if(b!=1) res=(res*b)%MOD; return res; } int main() { freopen("in.txt","r",stdin); getPrime(); int T; cin>>T; while(T--){ scanf("%d",&n); REP(i,1,n) scanf("%d",&a[i]); ll ans=1; MS0(vis); REP(i,1,n){ if(!vis[i]){ vis[i]=1; ll tmp=1; for(int j=a[i];j!=i;j=a[j]){ tmp++; vis[j]=1; } ans=lcm(ans,tmp)%MOD; } } printf("%lld ",ans%MOD); } return 0; }