[国家集训队]整数的lqp拆分
壹、题目描述 ¶
贰、题解 ¶
考虑到每种拆分的不同贡献,设 \(f(n)\) 表示拆分 \(n\) 的贡献,那么
\[f(n)=\sum_{i=0}^nfib(i)\times f(n-i) \\
F(x)=\sum_{n=0}^\infty\sum_{i=0}^n fib(i)f(n-i)x^n \\
F(x)=\sum_{i=0}^\infty fib(i)x^i\times \sum_{j=0}^\infty f(j)x^j \\
F(x)=G(x)F(x)+1 \\
F(x)={1\over 1-{x\over 1-x-x^2}}={1+{x\over 1-2x-x^2}} \\
\]
注意不要漏掉常数项 \(1\).
那么有
\[F(x)=1+{1\over 2\sqrt 2}\left({1\over 1-(1+\sqrt 2)x}-{1\over 1-(1-\sqrt 2)x}\right) \\
F(x)=1+\sum_i{1\over 2\sqrt 2}\left((1+\sqrt 2)^i-(1-\sqrt 2)^i \right)x^i \\
[x^n]F(x)={(1+\sqrt 2)^n-(1-\sqrt 2)^n\over 2\sqrt 2} \pmod p
\]
且 \(2\) 在 \(\bmod 10^9+7\) 下的二次剩余为 \(59713600\).
同时,\(n\) 在指数上,可以考虑使用欧拉定理降次,从而总复杂度为 \(\mathcal O(\log_{10}n)\)(因为你要读入
叁、参考代码 ¶
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
#define NDUBUG
#include<cassert>
namespace Elaina{
#define rep(i, l, r) for(int i=(l), i##_end_=(r); i<=i##_end_; ++i)
#define drep(i, l, r) for(int i=(l), i##_end_=(r); i>=i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define mmset(a, b) memset(a, b, sizeof a)
// #define int long long
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template<class T>inline T fab(T x){ return x<0? -x: x; }
template<class T>inline void getmin(T& x, const T rhs){ x=min(x, rhs); }
template<class T>inline void getmax(T& x, const T rhs){ x=max(x, rhs); }
template<class T>inline T readin(T x){
x=0; int f=0; char c;
while((c=getchar())<'0' || '9'<c) if(c=='-') f=1;
for(x=(c^48); '0'<=(c=getchar()) && c<='9'; x=(x<<1)+(x<<3)+(c^48));
return f? -x: x;
}
template<class T>inline void writc(T x, char s='\n'){
static int fwri_sta[1005], fwri_ed=0;
if(x<0) putchar('-'), x=-x;
do fwri_sta[++fwri_ed]=x%10, x/=10; while(x);
while(putchar(fwri_sta[fwri_ed--]^48), fwri_ed);
putchar(s);
}
}
using namespace Elaina;
const int Mod=1e9+7;
const int phiMod=Mod-1;
const int sqrt2=59713600;
const int maxl=1e4;
inline int qkpow(int a, int n){
int ret=1;
for(; n>0; n>>=1, a=1ll*a*a%Mod)
if(n&1) ret=1ll*ret*a%Mod;
return ret;
}
char s[maxl+5];
int len, n;
signed main(){
scanf("%s", s); len=strlen(s);
for(int i=0; i<len; ++i)
n=(10ll*n+(s[i]^48))%phiMod;
writc(1ll*(qkpow(1+sqrt2, n)+Mod-qkpow(1+Mod-sqrt2, n))*qkpow(2ll*sqrt2%Mod, Mod-2)%Mod);
return 0;
}