haraduka's diary

やる気が欲しい

ARC033 D問題

多項式の値、f(0), f(1), …, f(N)が与えられるから、f(T)を出力しろ、という問題。
単純にラグランジェ補間でよい。
逆元を求める際はextgcdとmod_inverseを使ってあげる。

ll mod = (ll)1e9+7;

// extgcd
// ax+by = gcd(a,b)の階を生成する。返り値はgcd(a, b)
// gcd(a,b) == 1のときはx, yが必ず存在している
template<class T>
T extgcd(T a, T b, T& x, T& y) {
    T d = a;
    if (b != 0) {
        d = extgcd(b, a % b, y, x);
        y -= (a / b) * x;
    } else {
        x = 1; y = 0;
    }
    return d;
}

// mod_inverse
// a*x == 1(mod m)となるxを生成する。つまり逆元を求める。
// ただしmが素数の時しか使えない。
// ax = 1+mkを求めることと同値だからextgcdを使っている
template<class T>
T mod_inverse(T a, T m = mod) {
    T x, y;
    extgcd(a, m, x, y);
    return (m+x%m) % m;
}

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    ll N; cin >> N;
    ll A[N+1];
    for(ll i=0; i<=N; i++){
        cin >> A[i];
    }
    ll T; cin >> T;
    ll C[N+1];
    ll res = 0;
    ll wari = 1;
    ll wari2 = 1;
    for(ll j=0; j<=N; j++){
        wari2 *= (T-j);
        wari2 %= mod;
    }
    while(wari2 < 0) wari2 += mod;
    for(ll i=0; i<=N; i++){
        C[i] = A[i];
        if(i == 0){
            for(ll j=0; j<=N; j++){
                if(i != j){
                    wari *= (i-j);
                    wari %= mod;
                }
            }
        }else{
            wari *= (i-0);
            wari %= mod;
            wari *= mod_inverse((i-1)-N+mod, mod);
            wari %= mod;
        }
        while(wari < 0) wari += mod;
        C[i] *= mod_inverse(wari, mod);
        C[i] %= mod;

        ll tmp = wari2 * mod_inverse(T-i, mod);
        tmp %= mod;
        while(tmp < 0) tmp += mod;

        res += C[i]*tmp;
        res %= mod;
    }
    cout << res << endl;
}