您的位置:首页 > 其它

【HDU】5275 pog loves szh IV【拉格朗日插值法】

2015-06-29 19:40 288 查看
传送门:【HDU】5275 pog loves szh IV

题目分析:首先,队友给了我一个拉格朗日插值法的公式,裸的OWO,如下:

∑i=lr{yi∏i!=j(xi−xj)∏i!=j(x−xj)}\sum_{i=l}^{r}\{\frac{y_i}{\prod_{i!=j}(x_i-x_j)}\prod_{i!=j}(x-x_j)\}

只要把题目给的坐标带入xi,xj,yi,xx_i,x_j,y_i,x,就可以求出答案了……

然后我们要怎么求呢?首先要求xi−xjx_i-x_j的逆元,因为最多只有500000种,且分布在[-250000,250000],且关于y轴−x-x的逆元和xx的逆元互为相反数,于是我们只用求[1,250000]内的逆元即可。

然后对于∏i!=j(xi−xj)\prod_{i!=j}(x_i-x_j),我们可以O(N2)O(N^2)预处理。然后每次查询,∏i!=j(x−xj)\prod_{i!=j}(x-x_j)是可以预先算的,因为∏i!=j(x−xj)=∏(x−xj)x−xi\prod_{i!=j}(x-x_j)=\frac{\prod(x-x_j)}{x-x_i},这里我们需要注意的一点是,x−xix-x_i可能为0,此时没有逆元,这时候因为xix_i各不相同,于是x−xix-x_i等于0的项最多出现一次,这时候我们暴力算就行了。

于是总复杂度为O(N2+NQ)O(N^2+NQ)

my code:my~~code:

[code]#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;

#define clr( a , x ) memset ( a , x , sizeof a )
#define cpy( a , x ) memcpy ( a , x , sizeof a )

const int MAXN = 3005 ;
const int MAXM = 250005 ;
const int mod = 1e9 + 7 ;

int mul[MAXN][MAXN] ;
int inv[MAXM] ;
int p[MAXN][2] ;
int n , q ;

int power ( int a , int b ) {
    LL res = 1 , tmp = a ;
    for ( ; b ; b >>= 1 , tmp = tmp * tmp % mod ) {
        if ( b & 1 ) res = res * tmp % mod ;
    }
    return res ;
}

void preprocess () {
    for ( int i = 1 ; i <= n ; ++ i ) {
        mul[i][i] = 1 ;
        for ( int j = i + 1 ; j <= n ; ++ j ) {
            mul[i][j] = ( LL ) mul[i][j - 1] * inv[abs ( p[i][0] - p[j][0] )] % mod * ( p[i][0] < p[j][0] ? -1 : 1 ) ;
            if ( mul[i][j] < 0 ) mul[i][j] += mod ;
        }
        for ( int j = i - 1 ; j >= 1 ; -- j ) {
            mul[i][j] = ( LL ) mul[i][j + 1] * inv[abs ( p[i][0] - p[j][0] )] % mod * ( p[i][0] < p[j][0] ? -1 : 1 ) ;
            if ( mul[i][j] < 0 ) mul[i][j] += mod ;
        }
    }
}

void solve () {
    int l , r , x ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        scanf ( "%d%d" , &p[i][0] , &p[i][1] ) ;
    }
    preprocess () ;
    scanf ( "%d" , &q ) ;
    for ( int i = 1 ; i <= q ; ++ i ) {
        scanf ( "%d%d%d" , &l , &r , &x ) ;
        int res = 0 , tot = 1 ;
        for ( int j = l ; j <= r ; ++ j ) {
            tot = ( LL ) tot * ( x - p[j][0] ) % mod ;
        }
        for ( int j = l ; j <= r ; ++ j ) {
            int tmp = ( LL ) p[j][1] * mul[j][l] % mod * mul[j][r] % mod ;
            if ( x != p[j][0] ) tmp = ( LL ) tmp * tot % mod * inv[abs ( x - p[j][0] )] % mod * ( x < p[j][0] ? -1 : 1 ) ;
            else {
                int t = 1 ;
                for ( int k = l ; k <= r ; ++ k ) {
                    if ( k != j ) t = ( LL ) t * ( x - p[k][0] ) % mod ;
                }
                tmp = ( LL ) tmp * t % mod ;
            }
            if ( tmp < 0 ) tmp += mod ;
            res = ( res + tmp ) % mod ;
        }
        printf ( "%d\n" , res ) ;
    }
}

int main () {
    inv[0] = 1 ;
    for ( int i = 1 ; i < MAXM ; ++ i ) {
        inv[i] = power ( i , mod - 2 ) ;
    }
    while ( ~scanf ( "%d" , &n ) ) solve () ;
    return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: