• 【ybt金牌导航8-3-2】数列求值


    数列求值

    题目链接:ybt金牌导航8-3-2

    题目大意

    给出一个不超过 m-1 次的函数,给出 x 为 0~m-1 时 y 的值,然后求 x 为 k 时 y 的值。

    思路

    这一题看到函数自然会想到拉格朗日插值法。

    但是你会看到它的范围很大,(n^2) 是过不了的。

    但是你会发现它有一个特殊的地方:给出的点是连续的,而且 (x_i=i)

    那你考虑能不能化简式子。
    先把式子拿出来:
    (f(k)=sumlimits_{i=1}^{n}(y_iprodlimits_{i eq j}dfrac{k-x_j}{x_i-x_j}))
    然后 (x_i=i)
    (f(k)=sumlimits_{i=1}^{n}(y_iprodlimits_{i eq j}dfrac{k-j}{i-j}))
    那累乘的不等号条件很烦,我们就把它分开乘两个累乘:
    (f(k)=sumlimits_{i=1}^{n}(y_iprodlimits_{1leq j<i}dfrac{k-j}{i-j}prodlimits_{i<jleq n}dfrac{k-j}{i-j}))
    那这里我们就发现它分子的部分分别是可以用前缀积和后缀积解决。

    然后再看分母,你会发现它是两个阶乘。

    那你就预处理这三个东西,就可以用了。

    在处理阶乘的时候,我们可以预先把它的逆元算出来。
    然后不要一个一个都转逆元,会 T,你可以求出最大的那个的逆元,然后每次再乘回去,就可以得到较小的阶乘的逆元了。

    还有。
    不要以为我的题意写错了。
    给出的就是从 (0sim m-1) 的,题目是有问题的,连样例都错了。
    正确的样例输出的应该是 (9),而不是 (7)

    然后我这里因为是后面才发现,就把它改成了从 (0) 开始记录数组,运算什么的。
    上面的公式的循环范围也要小改一下,这里就不再写一次了。
    (如果不知道怎么改可以看代码)

    代码

    #include<cstdio>
    #define ll long long
    #define mo 998244353
    
    using namespace std;
    
    ll m, k, a[1000001];
    ll y[1000001];
    ll q[1000001], b[1000001];
    ll jc[1000001], ans, now;
    
    ll ksm(ll x, ll y) {//快速幂求逆元
    	if (x < 0) x = (x % mo + mo) % mo;
    	
    	ll re = 1;
    	while (y) {
    		if (y & 1) re = (re * x) % mo;
    		x = (x * x) % mo;
    		y >>= 1;
    	}
    	
    	return re;
    }
    
    int main() {
    	scanf("%lld %lld", &m, &k);
    	m--;
    	
    	q[0] = k - 0;
    	scanf("%d", &y[0]);
    	for (ll i = 1; i <= m; i++) {
    		scanf("%lld", &y[i]);
    		
    		q[i] = q[i - 1] * ((k - i + mo) % mo) % mo;//处理分子的前缀积
    	}
    	
    	b[m + 1] = 1ll;
    	for (ll i = m; i >= 0; i--) {//处理分子的后缀积
    		b[i] = b[i + 1] * ((k - i + mo) % mo) % mo;
    	}
    	
    	jc[0] = 1ll;//求分母的阶乘
    	for (ll i = 1; i <= m; i++)
    		jc[i] = jc[i - 1] * i % mo;
    	jc[m] = ksm(jc[m], mo - 2);//现在就把分母的阶乘的逆元弄好
    	for (ll i = m - 1; i >= 0; i--)
    		jc[i] = (jc[i + 1] * (i + 1)) % mo;//不要每个都求逆元,会T
    	
    	for (ll i = 0; i <= m; i++) {
    		now = y[i];//按照公式乘
    		now = (now * (((i - 1 < 0) ? 1 : q[i - 1]) * b[i + 1] % mo)) % mo;
    		now = (now * (jc[i] * jc[m - i] % mo)) % mo;
    		now = (now * ((m - i) & 1 ? -1 : 1)) % mo;
    		if (now < 0) now += mo;
    		
    		ans = (ans + now) % mo;
    	}
    	
    	printf("%lld", ans);
    	
    	return 0;
    }
    
    
  • 相关阅读:
    HDU_2191_多重背包
    HDU_1494_dp
    POJ_1088_dfs
    所有的畅通工程[HDU1232][HDU1874][HDU1875][HDU1879]
    畅通工程[HDU1863]
    还是畅通工程[HDU1233]
    最小生成树
    Who's in the Middle[HDU1157]
    Bungee Jumping[HDU1155]
    Is It A Tree?[HDU1325][PKU1308]
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_8-3-2.html
Copyright © 2020-2023  润新知