1. 程式人生 > 實用技巧 >HDU6467 簡單數學題

HDU6467 簡單數學題

HDU6467 簡單數學題

思路:

簡單變換,先推式子

\[F(n) = \sum_{i=1}^n (i \times \sum_{j=i}^n C_j^i)\\ = \sum_{i=1}^n i \times \sum_{j=i}^n{j \choose i}\\ =\sum_{j=1}^n\sum_{i=1}^j i \times C_j^i\\ =\sum_{j=1}^nj2^{j-1}\\ =\frac{\sum_{j=1}^nj2^j}{2}\\ 至此,便得到了O(Tn)的演算法,顯然過不了\\ 發現無法從式子入手,可考慮數列分治\\ 轉換為已知F(n)求F(2n)\\ 易得,F(2n)=(F(n)+n\sum_{i=1}^n2^n)2^n,累和轉換為等比數列求和\\ 時間複雜度為O(Tlog^2n),依然過不了\\ 考慮將數列分治與快速冪合併,時間複雜度O(Tlogn),詳見程式碼 \]

#include<map>
#include<cmath>
#include<stack>
#include<deque>
#include<queue>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
# define Type template<typename T>
# define ll long long
# define read read1<ll>()
Type T read1(){
    T t=0;char k;
    bool v=0;
    do (k=getchar())=='-'&&(v=1);while('0'>k||k>'9');
    while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
    return v?-t:t;
}
ll qkpow(ll n,ll x,ll mo){
    if(!x)return 1;
    ll t=qkpow(n,x>>1,mo);
    t=t*t%mo;
    if(x&1)t=t*n%mo;
    return t;
}
# define mod 1000000007ll
# define I 500000004ll
ll q2(ll x){return qkpow(2,x,mod);}
ll w;
ll get(ll x){
    if(x==1){w=2;return 2;}
    ll mid=x>>1,v=get(mid),tl=(w*2+mod-2)%mod;
    v=(v+(v+mid%mod*tl)%mod*w)%mod;
    w=w*w%mod;
    if(x&1)w=w*2%mod,v=(v+x%mod*w)%mod;
    return (v+mod)%mod;
}
int main(){
    ll n;
    while(~scanf("%lld",&n))
        printf("%lld\n",get(n)*I%mod);
    return 0;
}