The Luckiest number POJ - 3696 (尤拉定理)
阿新 • • 發佈:2018-12-25
題目大意:對於給定的整數L,找出L能整除最短的全8序列的長度,做為Bob的幸運數字。
解析:一開始做這個題的時候直接莽夫式做法 ,列舉8的位數,交一發直接wa,想想也是,沒給8的位數的上限,暴力列舉8的話肯定要爆longlong的。 。。
正確的做法居然是用尤拉定理。我們可以通過題意列出下式:8/9 * (10^x-1)=L * p
根據尤拉定理我們知道:10^Φ(m)≡1(mod m)。 我們要做的就是把根據題目推出來的式子化成尤拉定理的式子(這個具體的推導過程真的沒想出來,參考了大神的部落格才懂:戳這裡) 具體就不贅述了,程式碼描述的還是很清楚的。
#include<iostream> #include<cstdio> #define ll long long using namespace std; struct node{ ll cnt; ll p; }; node num[100]; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; } ll Euler(ll n){//尤拉函式 ll ret=1,i; for(i=2;i*i<=n;i++){ if(n%i==0){ n/=i;ret*=i-1; while(n%i==0){ n/=i;ret*=i; } } } if(n>1)ret*=n-1; return ret; } ll solve(ll n){//基本算數定理 用num記錄下n由那些素陣列成,這些素數分別有幾個 int t=0; for(ll i=2;i*i<n;i++){ if(n%i==0){ num[t].p=i; num[t].cnt=0; while(n%i==0){ num[t].cnt++; n/=i; } t++; } } if(n>1){ num[t].p=n; num[t].cnt=1; t++; } return t;//返回素數的種類 } ll multi(ll a,ll b,ll c) {//由於爆int 所以用的快速乘法和快速冪 ll ans = 0; while (b) { if (b & 1) { ans += a;ans %= c; } a += a;a %= c; b >>= 1; } return ans; } ll Pow(ll a, ll b, ll c) { ll ans = 1; while (b) { if (b & 1) { ans = multi(ans, a, c); } a = multi(a, a, c); b >>= 1; } return ans; } int main(){ ll L; int ca=1; while(cin>>L,L){ ll m=9*L/gcd(L,8); if(gcd(10,m)!=1){ printf("Case %d: 0\n",ca++); continue; } ll pi=Euler(m); ll cnt=solve(pi); for(int i=0;i<cnt;i++){//縮小pi,找到滿足條件的最小的pi for(int j=0;j<num[i].cnt;j++){ if(Pow(10,pi/num[i].p,m)==1){ pi/=num[i].p; } } } printf("Case %d: %lld\n",ca++,pi); } return 0; }