洛谷P4451 [国家集训队]整数的lqp拆分 [生成函数]

传送门

题意简述:语文不好不会写,自己看吧

思路如此精妙,代码如此简洁,实是锻炼思维水经验之好题


这种题当然是一眼DP啦。

\(dp_n\)为把\(n\)拆分后的答案。为了方便我们设\(dp_0=1\)

由题意有
\[ dp_n=[n=0]+\sum_{i=1}^n dp_{n-i}f_i \]
按照套路,我们考虑它的生成函数\(A(x)\)
\[ \begin{align*} A(x)&=\sum_n ([n=0]+\sum_{i=1}^n f_i dp_{n-i})x^n\\ &=1+\sum_{n=1}^{\infty} (\sum_{i=1}^n f_i dp_{n-i})x^n\\ &=1+\sum_n (\sum_{i=0}^n f_i dp_{n-i})x^n//多枚举一点不会造成影响\\ &=1+A(x)F(x) \end{align*} \]
我们知道\(F(x)=\frac{x}{1-x-x^2}\),所以有
\[ \begin{align*} A(x)&=\frac{1}{1-F(x)}\\ &=1+\frac{x}{1-2x-x^2}\\ &=1+\frac{1}{2\sqrt{2}}(\frac{1}{1-(1+\sqrt{2})x}-\frac{1}{1-(1-\sqrt{2})x})\\ &=1+\sum_n \frac{1}{2\sqrt{2}}[(1+\sqrt{2})^n-(1-\sqrt{2})^n] \end{align*} \]
所以
\[ Ans_n=\frac{(1+\sqrt{2})^n-(1-\sqrt{2})^n}{2\sqrt{2}} \]
发现题目要求\(Ans_n\pmod{1e9+7}\),枚举可得$59713600^2 \equiv 2\pmod{1e9+7} $ ,所以\(\sqrt{2}\equiv 59713600 \pmod{1e9+7}\)

于是我们在\(O(\log n)\)的时间内求得了答案!

问题来了:为什么数据范围只有\(10^6\)呢?我\(O(\log n)\)快速幂还没有\(O(n)\)递推快……

代码:

#include<bits/stdc++.h>
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define sz 101010
    #define mod (int)(1e9+7)
    typedef long long ll;
    template<typename T>
    inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();
        double d=0.1;
        while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
        if(ch=='.')
        {
            ch=getchar();
            while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();
        }
        t=(f?-t:t);
    }
    template<typename T,typename... Args>
    inline void read(T& t,Args&... args){read(t); read(args...);}
    void file()
    {
        #ifndef ONLINE_JUDGE
        freopen("a.txt","r",stdin);
        #endif
    }
//  inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

const ll sqrt2=59713600;
ll ksm(ll x,int y)
{
    ll ret=1;
    for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;
    return ret;
}
ll inv(ll x){return ksm(x,mod-2);}
int n;

int main()
{
    file();
    read(n);
    cout<<(ksm(1+sqrt2,n)-ksm(mod+1-sqrt2,n)+mod)%mod*inv(2*sqrt2)%mod;
}

猜你喜欢

转载自www.cnblogs.com/p-b-p-b/p/10349253.html