1. 程式人生 > >[JLOI2015]有意義的字符串

[JLOI2015]有意義的字符串

同余 方程 問題 有意 pos ons brush 個數 out

4002: [JLOI2015]有意義的字符串

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1000 Solved: 436
[Submit][Status][Discuss]

Description

B 君有兩個好朋友,他們叫寧寧和冉冉。有一天,冉冉遇到了一個有趣的題目:輸入 b;d;n,求

技術分享圖片

Input

一行三個整數 b;d;n

Output

一行一個數表示模 7528443412579576937 之後的結果。

Sample Input

1 5 9

Sample Output

76

HINT

其中 0<b^2< = d<(b+1)2< = 10^18,n< = 10^18,並且 b mod 2=1,d mod 4=1

一開始幼稚的以為可以把sqrt(d)在%7528443412579576937 同余系下表示成一個整數,但後來發現我太naive了。 可以先找到((b+sqrt(d))/2)^n的共軛函數((b-sqrt(d))/2)^n,設這兩者的和為f[n]。 那麽我們相當於知道了兩個基底等比數列,來構造出f[i]的遞推式。 顯然兩個基底的只能是和前兩項有關,於是我們設f[i+2]+ k * f[i+1] + p * f[i] =0 那麽,可以得到 x^2 + k*x + p =0。 這個方程的兩個根分別是 (b+sqrt(d))/2 和 (b-sqrt(d))/2 所以我們帶回去就可以求得k和p。 然後就可以開開心心的 用矩陣快速冪求 f[n]了。
但問題是怎麽減去共軛函數的另一支呢? 有一個結論是當且僅當 b==d^2且n為偶數的時候需要-1,但是我也不知道為什麽2333。
#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const ll ha=7528443412579576937ll;

inline ll add(ll x,ll y){
	x+=y;
	return x>=ha?x-ha:x;
}

inline ll ksc(ll x,ll y){
	ll an=0;
	for(;y;y>>=1,x=add(x,x)) if(y&1) an=add(an,x);
	return an;
}

inline ll ksm(ll x,ll y){
	ll an=1;
	for(;y;y>>=1,x=ksc(x,x)) if(y&1) an=ksc(an,x);
	return an;
}

const ll inv=ksm(2,ha-2);
const ll INV=ksc(inv,inv);
ll B,D,N;
struct node{
	ll a[2][2];
	
	node operator *(const node &u)const{
		node r;
		for(int i=0;i<=1;i++)
		    for(int j=0;j<=1;j++){
		    	r.a[i][j]=add(ksc(a[i][0],u.a[0][j]),ksc(a[i][1],u.a[1][j]));
			}
		return r;
	}
}ans,x;

inline void solve(){
	ans.a[0][0]=ans.a[1][1]=1;
	ans.a[0][1]=ans.a[1][0]=0;
	
	ll O=N;
	N--;
	for(;N;N>>=1,x=x*x) if(N&1) ans=ans*x;
	
	ll an=0;
	an=add(ksc(2,ans.a[0][1]),ksc(B,ans.a[1][1]));
	
	if(ksc(B,B)!=D&&!(O&1)) an=add(an,ha-1);
	printf("%lld\n",an);
}

int main(){
	scanf("%lld%lld%lld",&B,&D,&N);
	if(!N){
		puts("1");
		return 0;
	}
    
	x.a[0][0]=0;
	x.a[1][0]=1;
	x.a[1][1]=B;
	x.a[0][1]=(D-ksc(B,B))>>2;
	
	solve();
	
	return 0;
}

  

[JLOI2015]有意義的字符串