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

传送门:【HDU】5275 pog loves szh IV

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

i=lr{yii!=j(xixj)i!=j(xxj)}

只要把题目给的坐标带入 xi,xj,yi,x ,就可以求出答案了……
然后我们要怎么求呢?首先要求 xixj 的逆元,因为最多只有500000种,且分布在[-250000,250000],且关于y轴 x 的逆元和 x 的逆元互为相反数,于是我们只用求[1,250000]内的逆元即可。
然后对于 i!=j(xixj) ,我们可以 O(N2) 预处理。然后每次查询, i!=j(xxj) 是可以预先算的,因为 i!=j(xxj)=(xxj)xxi ,这里我们需要注意的一点是, xxi 可能为0,此时没有逆元,这时候因为 xi 各不相同,于是 xxi 等于0的项最多出现一次,这时候我们暴力算就行了。

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

my  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 ;
}

你可能感兴趣的:(插值)