• CF622F:The Sum of the k-th Powers


    Pre

    写一份(O(n))的代码,作为参考。

    这东西坑点比较多。

    我的代码当中多开了几个数组,因为我太懒了便于理解。

    Solution

    首先,我们找到正解(拉格朗日差值具体就不讲了)。

    发现需要维护:

    阶乘的连乘的逆元

    由于是从(1)开始,需要的空间不算大,所以可以(O(k))处理,下一个。

    (prodlimits_{i=1}^nx-i)

    这个不是逆元,可以求出每一个元素,连乘再求逆元,按套路就可以了。

    (nleq k+2)时的答案

    为了保证时间复杂度严格为(O(k)),这个应该线性筛。

    Code

    #include <cstdio>
    using namespace std;
    const int N = 1000000 + 5, mod = 1000000007;
    inline int mul (int a, int b) {return 1LL * a * b % mod;}
    inline int add (int a, int b) {return a + b >= mod ? a + b - mod : a + b;}
    inline int mns (int a, int b) {return a - b < 0 ? a - b + mod : a - b;}
    inline int qpow (int u, int v) {
    	int tot = 1, base = u % mod;
    	while (v) {
    		if (v & 1) tot = mul (tot, base);
    		base = mul (base, base);
    		v >>= 1;
    	}
    	return tot;
    }
    int x, k;
    struct DuLiu {
    	int pri[N + 5], tot, res[N + 5];
    	bool vis[N + 5];
    	inline void init () {
    		int n = k + 2;
    		res[1] = 1;
    		for (int i = 2; i <= n; ++i) {
    			if (!vis[i]) {
    				pri[++tot] = i;
    				res[i] = qpow (i, k);
    			}
    			for (int j = 1; j <= tot; ++j) {
    				if (pri[j] * i > n) break;
    				vis[i * pri[j]] = 1;
    				res[i * pri[j]] = mul (res[i], res[pri[j]]);
    				if (i % pri[j] == 0) break;
    			}
    		}
    		for (int i = 2; i <= n; ++i) res[i] = add (res[i - 1], res[i]);
    	}
    }num;
    int fac[N + 5], fac_prod[N + 5], fac_prod_inv[N + 5], extra, mid[N + 5], mid_prod[N + 5], mid_prod_inv[N + 5], mid_inv[N + 5];
    inline void init_mid () {
    	int n = k + 2;
    	for (int i = 1; i <= n; ++i) mid[i] = x - i; mid[0] = x;
    	mid_prod[0] = 1; for (int i = 1; i <= n; ++i) mid_prod[i] = mul (mid_prod[i - 1], mid[i]);
    	mid_prod_inv[n] = qpow (mid_prod[n], mod - 2);
    	for (int i = n - 1; i >= 0; --i) mid_prod_inv[i] = mul (mid_prod_inv[i + 1], mid[i + 1]);
    	for (int i = 1; i <= n; ++i) mid_inv[i] = mul (mid_prod_inv[i], mid_prod[i - 1]);
    	mid_inv[0] = qpow (x, mod - 2);
    }
    inline void Lagrange () {
    	int ans = 0, n = k + 2;
    	for (int i = 1; i <= n; ++i) {
    		int tmp = 1, f = 1;
    		tmp = mul (tmp, mul (fac_prod_inv[i - 1], i - 2 >= 0 ? fac_prod[i - 1 - 1] : 1));
    		tmp = mul (tmp, mul (fac_prod_inv[n - i], n - i - 1 >= 0 ? fac_prod[n - i - 1] : 1));
    		if ((n - i) % 2 == 1) f *= -1;
    		int liujuakioi = mid_prod[n];
    		tmp = mul (tmp, mul (liujuakioi, mid_inv[i]));
    		tmp = mul (tmp, num.res[i]);
    		if (f > 0) ans = add (ans, tmp);
    		else ans = mns (ans, tmp);
    	}
    	printf ("%d
    ", ans);
    }
    int main () {
    	scanf ("%d%d", &x, &k);
    	num.init ();
    	if (x <= k + 2) {printf ("%d
    ", num.res[x]); return 0;}
    	fac[0] = 1; for (int i = 1; i <= N; ++i) fac[i] = mul (fac[i - 1], i);
    	fac_prod[0] = 1; for (int i = 1; i <= N; ++i) fac_prod[i] = mul (fac_prod[i - 1], fac[i]);
    	fac_prod_inv[N] = qpow (fac_prod[N], mod - 2);
    	for (int i = N - 1; i >= 0; --i) fac_prod_inv[i] = mul (fac_prod_inv[i + 1], fac[i + 1]);
    	init_mid();
    	Lagrange ();
    	return 0;
    } 
    

    Conclusion

    细节比较多,交了好几次才过。

    注意(Lagrange)函数里面的变量的使用,易错(实际上是我写得太麻烦, 貌似阶乘的单独逆元另外开一个数组更加方便)。

  • 相关阅读:
    再起航,我的学习笔记之JavaScript设计模式13(装饰者模式)
    在 ASP.NET Core 中执行租户服务
    再起航,我的学习笔记之JavaScript设计模式12(适配器模式)
    再起航,我的学习笔记之JavaScript设计模式11(外观模式)
    再起航,我的学习笔记之JavaScript设计模式10(单例模式)
    Entity Framework Core 2.0 全局查询过滤器
    再起航,我的学习笔记之JavaScript设计模式09(原型模式)
    APScheduler
    Gvim打造python编辑器,附自己的配置文件
    Python通过logging记录日志并应用coloredlogs在控制台输出有色字体
  • 原文地址:https://www.cnblogs.com/ChiTongZ/p/11304841.html
Copyright © 2020-2023  润新知