自然數冪/次方數前綴和公式推導


之前訓練賽上碰到了這么一道題:Problem - E - Codeforces
要求 \(\sum_{i=1}^n i^5\ (n~is~so~big)\)​​,一般只會記平方數,立方數前綴和公式。這倆我都經常記不住
好在之前學過如果通過低次的次方數前綴和推到高次,但寫這題的時候忘了,又滾去百度了一波。
為了加深記憶,寫個博客記錄下到底是怎么推的。
話說 \(i^k\) 到底是叫次方數還是叫自然數冪來着?

已知 \(\sum_{i=1}^n i=\dfrac {n*(n+1)}2\)​​,求 \(\sum_{i=1}^n i^2\)​​:

\[\sum_{i=1}^n (i+1)^3=\sum_{i=1}^n (i^3+3i^2+3i+1)\\ (n+1)^3-1=3\sum_{i=1}^n i^2+3\sum_{i=1}^n i^2+n\\ \sum_{i=1}^n i^2=\frac {(n+1)^3-n-1}{3}-\frac{n(n+1)}{2}=\frac {n(n+1)(n+2)}{6} \]

同理,要求立方數的前綴和公式,則對 \(\sum_{i=1}^n (i+1)^4\)​​ 進行同樣的操作,同時我們也可從中得出一個結論:\(n\) 次方數的前綴和公式一定是個 \(n+1\) 次多項式。

這樣推在高次的時候會挺麻煩的,可能要在草稿紙上算挺久化簡化一年,但確實簡單易懂,好想好記。

而且如果時間復雜度允許的話,也不用特意花大量時間去計算式子並化簡、然后套公式 \(O(1)\)​​ 求解;只需在草稿紙上根據二項式定理多展開幾項,然后寫好對應的函數 calx(n) 計算\(\sum_{i=1}^n i^x\)​​,類似遞歸地調用一下即可,時間復雜度也是常數級的。

比如要求 \(i^7\)​​​​​​​​​​​​​​​​​ 次方,那我們把 \(i^{4+1}\sim i^{7+1}\)​​​​​​​​​​​​​​​​​ 都展開一下,然后 ​​cal7(n) 調用 cal6(n) 調用 cal5(n)。。。一直到 cal3(n)(一般立方數的前綴和我們知道)遞歸結束。假遞歸,每個函數都不一樣

也許可以寫個函數指針數組?沒研究過,不太清楚,但腦補一下感覺好像可行。

感覺可能還有更好的方法來求解次方數前綴和問題?但私以為這個就夠用了,於是就懶得去找了,總之先放這兒,以后如果學到了啥更優秀的方法再回頭更新一波。估計是莫得了

順便貼一下該題的代碼,二分 + Java 處理大數。訓練時寫的,賊丑,慎看

import java.math.BigInteger;
import java.util.Scanner;

class Main {
    static BigInteger cal(BigInteger x){
        BigInteger x2=x.multiply(x);
        BigInteger x1=x.add(BigInteger.ONE);
        x1=x1.multiply(x1);
        BigInteger ret=x2.multiply(x1);
//        System.out.println(ret);
        x=x.multiply(BigInteger.valueOf(2));
        x2=x2.add(x2);
        ret=ret.multiply(x.add(x2).subtract(BigInteger.ONE));
        ret=ret.divide(BigInteger.valueOf(12));
        return ret;
    }
    public static void main(String[] args) {
        String P=new String();
        String Q=new String();
        Scanner in =new Scanner(System.in);
        P=in.next();
        Q=in.next();
        BigInteger p=new BigInteger(P);
        BigInteger q=new BigInteger(Q);
//        System.out.println(p.divide(q));
        BigInteger x=BigInteger.ZERO;
        BigInteger ans=BigInteger.ZERO;
        BigInteger d=BigInteger.ONE;
        for(long i=1;;i++){
            BigInteger ti=BigInteger.valueOf(i).pow(5);
            BigInteger tx=ti.multiply(q);
            if(tx.compareTo(p)>=0){
                d=BigInteger.valueOf(i);
                ans=tx;
                break;
            }
            x=x.add(tx);
            x=x.subtract(p);
//            x=x.add(tx);
//            x=x.subtract(p);
//            if(x.multiply(BigInteger.valueOf(-1)).compareTo(p)>=0||tx.compareTo(p)>=0){
//                d=BigInteger.valueOf(i);
//                ans=tx;
//                break;
//            }
        }
//        System.out.println("x = "+x);
//        System.out.println("d = "+ d);
            x=p.subtract(x);
        System.out.println(x);
//        System.out.println(d);
//        System.out.println(cal(d));
        BigInteger dt=cal(d);
        BigInteger mb=new BigInteger("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
        mb=mb.subtract(ans);
        BigInteger l=d.add(BigInteger.ONE);
        BigInteger r=new BigInteger("100000000000000000000");
        BigInteger y=l;
        while(l.compareTo(r)<=0){
            BigInteger mid=l.add(r).divide(BigInteger.valueOf(2));
//            System.out.println("mid = "+mid);
            BigInteger t=cal(mid).subtract(dt);
            t=t.multiply(q);
            BigInteger cj=mid.subtract(d);
            t=t.subtract(cj.multiply(p));
            if(t.compareTo(mb)>=0){
                y=mid;
                r=mid.subtract(BigInteger.ONE);
            }
            else {
                l=mid.add(BigInteger.ONE);
            }
        }
        System.out.println(y);
    }
}
2021.11.19

剛說不會學就學到新東西了好快のflag回收,用拉格朗日插值可以更加優美地解決此類問題,請移步:拉格朗日插值學習筆記 - olderciyuan - 博客園 (cnblogs.com)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM