"SDOI2010"고대 돼지 문화 루카스 +, 중국 잉여 정리

질문의 의미 :

문명 돼지 왕국의 오랜 역사, 심오한.

큰 돼지의 학교 도서관에서 정보 iPig 액세스, 즉 고대에 돼지 본문 텍스트의 총 수는 N입니다 물론, 언어 많은 단어 경우, 사전 그만큼 큰 것이다. 멀리 강희의 크기가 초과 할 수 수리 사전을 경우 그 당시 돼지의 왕국의 왕이 고려, 돼지 물질은 헤아릴 수없는 것, 힘을 보냈다. 그래서 다시 일을 생각하고 다시 어떤 노동자는 돈의 돼지 폐기물을 인용하지 않습니다. 물론, 역사적 변화와 단어 돼지 왕국 이후 점차적으로 자주 사용되는 단어의 일부를 제거, 단순화.

iPig 돼지 본문 텍스트의 고대 왕조를 연구 할 계획이다. k는 (1, N 일 수있다)의 N 양의 약수이고 관련 문헌에 따르면, 시대의 확산 돼지 본문 정확히 하나의 서브 고대는 케이. 그러나 특정 지점 k의 하나 무엇이며, k는 역사는 너무 길기 때문에, 추적하기 어려웠다, 수입니다.

들이 충족 문헌 iPig 각 N은 K로 나눌 가능하다. 그는 계정으로 가능한 모든 K를 취할 계획이다. k는 소정의 값과 동일 할 때 분명히의 본문 향해 돼지의 수 \ (\ FRAC {N}} {k 개의 \) . 그러나, 예비의 캐릭터로부터 N \ (\ FRAC {N} {
K} \) 번째 상황은 훨씬 더 많은 것이다. 경우의 수는 모든 가능한 모든 K를 추가하면 iPig이 예상되는 것은 P이다, 그는 P G의의 힘이 될 것입니다 비용의 고대 문헌을 공부했다.

이제 그는 돼지 캐릭터가의 고대 왕국의 비용을 알고 싶어한다. iPig 때문에이 그림은 천문학적 될 수 있다고 생각, 그래서 당신은 대답이 그것에 999,911,659으로 나누어 그에게 이야기해야합니다.

입력 :

Ancient.in 입력 파일과 하나의 라인 : 공간에 의해 분리 된 두 개의 숫자 N, G.

출력 :

부문 999 911 659의 나머지 부분에 대한 답을 나타내는 숫자 : 출력 파일 ancient.out은 오직 하나 개의 라인을 가지고있다.

아이디어 :

(시험이 완료되지 않은 경우를 나타냅니다)
도 1은, 제 \ (P \) 커야, 이는 모듈러스가 필요하다 \ (X \) 를 만족 \ (G를 ^ {P의 개조 된 X } \ 당량 G ^ P (MOD \ 모) \)

페르마의 작은 정리 된 \ (G ^ {모 -1- } \ equiv1 (MOD \ 모) \) 본 \ (X = -mod. 1 \) .
수있는 바와 \ (P는 \) 로 분할된다 \ (\ FRAC {P} { X} \) \ (X는 \) 을 곱하여 곱 \ (P의 %의 X를 \) 앞의 번호, \ (MOD \ ) 모듈의 경우에 ) (1 \를 \ 대답에 영향을 미치지 않을 것

2, 계산은 대상에 필요합니다 \ (G ^ {\ sum_ { X | N} C_ {N} ^ {X}} \) 그래서 우리는 조합의 수를 처리해야합니다.

그러나, 타이틀 \ (\ N-)의 최대 범위 (1,000,000,000 \)를 \ , 재귀 계산와 역원 직접 아니지만에서 찾을 수있다 \ (MOD-1 \) , 즉 소수의 네 가지 제품으로 분리 할 수 있고, \ (= 2 * 3 * 999 911 658 4679 35 617 * \) 만 가장 큰 곳 (\ 35,617 \)를 , 다음 사용하도록 선택할 수 있습니다 \ (루카스 \) 이제 과학은 입증되지

즉,이 같다 :

int lucas(int x,int y,int p) {
    if(y==0)return 1;
    return 1ll*calc(x%a[p],y%a[p],p)*lucas(x/a[p],y/a[p],p)%a[p];
}

(상기는 P 모듈러스 네 지칭)

우리는 조합의 수를 얻은 각 모듈 3. 다음 문제는 번호를 찾을로 변환된다

들면 \ (i∈ [1,4] \) 을 만족하는, \ (X \ 당량 B_i (MOD \ A_I) \)

이 공식은 또한 √, 중국 잉여 정리 해결을 사용할 수 있습니다

나는이 때 낯선 테스트되지 않습니다 있지만, 위에서 언급 한 점의 일부 지식은 매우 중요합니다

경우 참고 : \이 (G = 모 \) 대답을해야한다 \ (0 \)를 하지만, 루카스 해결에 따라 올 것이다 \ (1 \)를 , 특별한 문장을

잘 시간 카드, 당신은 역 선형을 밀어 선택할 수 있습니다.

다음과 같이 코드입니다 :

#include<bits/stdc++.h>
#define Mod 999911659
using namespace std;
int n,G,a[]= {2,3,4679,35617},b[4],pr[4][35620],ni[4][35620];
int mul(int x,int y,int mod) {
    int res=1;
    while(y) {
        if(y&1)res=1ll*res*x%mod;
        x=1ll*x*x%mod,y>>=1;
    }
    return res;
}
int calc(int x,int y,int p) {
    return 1ll*pr[p][x]*ni[p][y]%a[p]*ni[p][x-y]%a[p];
}
int lucas(int x,int y,int p) {
    if(y==0)return 1;
    return 1ll*calc(x%a[p],y%a[p],p)*lucas(x/a[p],y/a[p],p)%a[p];
}
int ans=0;
void exgcd(int A,int B,int &x,int &y) {
    if(B==0)x=1,y=0;
    else exgcd(B,A%B,y,x),y-=(A/B)*x;
}
void Calc(int x,int y) {
    int M=1;
    for(int i=0; i<4; i++)b[i]=lucas(x,y,i),M*=a[i];
    int tot=0;
    for(int i=0; i<4; i++) {
        int A=0,B=0,p=M/a[i];
        exgcd(p,a[i],A,B);//(A*p)%a[i]=1
        A=(A%a[i]+a[i])%a[i];
        tot=(tot+1ll*A*b[i]%M*p%M)%M;
    }
    ans=(ans+tot)%(Mod-1);
}
int main() {
    scanf("%d%d",&n,&G);
    int k=sqrt(n);
    for(int i=0; i<4; i++) {
        pr[i][0]=1,ni[i][0]=1;
        for(int j=1; j<=a[i]; j++)pr[i][j]=1ll*pr[i][j-1]*j%a[i],ni[i][j]=mul(pr[i][j],a[i]-2,a[i]);
    }
    if(Mod==G)printf("0\n");
    else {
        for(int i=1; i<=k; i++) {
            if(n%i)continue;
            int a=i,b=n/i;//c(n,a)+c(n,b)
            Calc(n,a);
            if(a!=b)Calc(n,b);
        }
        printf("%d\n",mul(G,ans,Mod));
    }
    return 0;
}

추천

출처www.cnblogs.com/cly1231/p/11355743.html