1. 程式人生 > 實用技巧 >POJ3696 尤拉定理

POJ3696 尤拉定理

看了兩天,poj還卡溢位。

題意

  給你一個數L(2e9),找到最小的連續8組成的數且是L的倍數。沒有則輸出0。

思路

  首先8個連續的數可以表示為(10x-1)*8/9。

  (10x-1)*8/9 = L*k(k為任意整數)

  (10x-1)*8 = L*k*9

  令d = gcd(8,L)。

  則兩邊同時除d

  (10x-1)*(8/d) = k*(L*9)/d

  由a*b=c*d且a,c互質,能推出b|c可得

  10x-1|9*L/d

  ze可以

  然後答案即為9L/d 的尤拉函式的約數。如果10和9L/d不互質,則無解。

  注意這題快速冪會溢位。

#include <iostream>
#include 
<cstdio> #include <cmath> using namespace std; typedef long long ll; ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} const int maxn = 2e5+10; ll L; ll phi(ll n) { ll ans = n; for(int i = 2;i <= sqrt(n); ++i){ if(n % i == 0){ ans = ans/i * (i-1); while(n%i==0
) n/=i; } } if(n > 1) ans = ans/n*(n-1); return ans; } ll powmod(ll a, ll b, ll mod) { ll sum = 1; while (b) { if (b & 1) { sum = (sum * a) % mod;b--; } b /= 2;a = a * a % mod; } return sum; } int main() { //freopen("input.txt", "r", stdin);
int casee = 0; while(scanf("%lld",&L) != EOF){ if(L == 0) break; ll d = gcd(L,8ll); ll p = 9*L/d; if(gcd(10,p) == 1){ ll k = phi(p); bool flag = 0; for(int i = 1;i <= sqrt(k);++i){ if(k%i==0 && powmod(10,i,p)==1){ printf("Case %d: %d\n",++casee,i ); flag = 1; break; } } if(flag == 1) continue; for(int i = sqrt(k);i >= 1;--i){ if(k%i==0 && powmod(10,k/i,p)==1){ printf("Case %d: %d\n",++casee,k/i ); break; } } }else printf("Case %d: 0\n",++casee ); } }