EGOI Legowall 简单计数题
xiaoyaowudi · · 题解
其他题解都是
第一种做法,直接容斥:
设
其中
第二种做法:
另外一种理解也可以得到上述式子:设联通的生成函数是
注意到
由于斐波那契数列第
其中
设
考虑如何求出
求出
平衡一下复杂度即为
代码:
#include <iostream>
#include <algorithm>
constexpr int N(5e5+10),p(1e9+7),_2((p+1)/2);
int fp(int a,int b){int ans(1),off(a);while(b){if(b&1) ans=1ll*ans*off%p;off=1ll*off*off%p;b>>=1;}return ans;}
int W(int k){return k>=p?k-p:k;}
int main()
{
int n,m;std::cin>>n>>m;
if(n<=m)
{
static int fib[N],f[N],g[N];fib[0]=g[0]=1;
for(int i(1);i<=n;++i)
{
fib[i]=W(fib[i-1]+(i>1?fib[i-2]:0));
f[i]=g[i]=fp(fib[i],m);
for(int j(0);j<i;++j) f[i]=(f[i]+1ll*(p-f[j])*g[i-j])%p;
}
std::cout<<f[n]<<std::endl;
}
else
{
static int f[N],fac[N],ifac[N],fib[N];int d(0);
fac[0]=1;for(int i(1);i<N;++i) fac[i]=1ll*fac[i-1]*i%p;
ifac[N-1]=fp(fac[N-1],p-2);for(int i(N-1);i;--i) ifac[i-1]=1ll*i*ifac[i]%p;
if(m%2==0)
{
d=1;f[0]=(m%4)?1:p-1;
f[1]=1;
}
else f[0]=1;
for(int i(2-(m&1));i<=m;i+=2)
{
int cur(0);
for(int j(0),t(fac[i]);j<=i;j+=2,t=5ll*t%p)
{
cur=(cur+1ll*t*ifac[j]%p*ifac[i-j])%p;
}
cur=1ll*cur*fp(_2,i-1)%p;
int b(((m-i)%4)?cur:p-cur);
static int g[N];
for(int t(0);t<=d+2;++t)
{
unsigned long long num((m&1)?p-f[t]:f[t]);
if(t) num+=1ll*b*f[t-1];
if(t>1) num+=f[t-2];
g[t]=num%p;
}
d+=2;
std::copy(g,g+d+1,f);
}
std::reverse(f,f+d+1);
static int F[N],H[N];
for(int i(0);i<d;++i)
{
if(i<2) fib[i]=1;
else fib[i]=W(fib[i-1]+fib[i-2]);
F[i]=fp(fib[i],m);
}
for(int i(0);i<d;++i)
{
for(int j(0);j<=i;++j) H[i]=(H[i]+1ll*f[j]*F[i-j])%p;
}
int iv(fp(H[0],p-2));
for(int i(0);i<=n;++i)
{
int v(f[i]);
for(int j(1);j<=i && j<d;++j) v=(v+1ll*(p-f[i-j])*H[j])%p;
f[i]=1ll*v*iv%p;
}
std::cout<<(p-f[n])%p<<std::endl;
}
return 0;
}