AtCoder AGC009E永遠の平均(DP)

トピックリンク

https://atcoder.jp/contests/agc009/tasks/agc009_e

問題の解決策

彼は落胆されています。
最初のステップは、変換明らかである:これは、開始番号に相当する\(1 \)\(\ FRAC {N + M -1}、{K-1} \) 番号を選択する機会たびにそれがなる\(K \)元番目\は(\ FRAC。1 {{}} Kは\) そして最後から(N + m個の\)\の選択された数\(m個\) aは、Qは選択することができるどのように多くの異なります番号。
その後に検討\(K \)仮定され形成された二進小数点の数、および最後に\(D_1、D_2、...、D_ {N-M} + \) 次いで(\ \和^ {N + M} _ { D_I 1} = = I. 1 \) \(D \)バイナリ画分は、のように表すことができる\(m個\)\(K \)のみのそれぞれの値の和ならあれば負の整数パワーを超えていない\(m個\)をし、そして\(m個\)モード\((K-1)\ ) 合同。(明らかに)も確保しながら、しかし、\を(1 \)のように表すことができる\((N + M)\ ) \(K \)

負の整数の累乗の和、および含まれて\(m個\)番号。それはに変換することができる\(1 \)これは、小数点以下のように表すことができる保存\(N- \)\(K \)負整数乗の和。(オーケー、私は......ああ......自閉症のうち、このステップを考えた)
だから、最後にはシーケンスの数を計算することです\(A_1、A_2、...、 a_l \(1 \ルリットル\ル\ FRAC {N- + M-1} {K-1})\)、満足\(0 \ルa_iを\ル K-1、a_l> 0、\和^ L_ {i = 1} a_iを\ルM、\和^ L_ {i = 1} a_iをする\の当量のM(\ MOD K-1)\和^ L_ {I = 1} K-1-a_iを\ル、N-1、\和^ L_ {I = 1} K-1 -a_i \ -n-当量1(\ K-MOD。1)\) 直接DPへ。時間複雑度\(O((N-M +)K)\)

コード

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cassert>
#define llong long long
using namespace std;

const int N = 4e3;
const int P = 1e9+7;
llong dp[N+3][N+3],sdp[N+3][N+3];
int n1,n2,m,len;
llong ans;

int main()
{
    scanf("%d%d%d",&n1,&n2,&m); len = (n1+n2-1)/(m-1);
    dp[0][0] = 1ll; for(int j=0; j<=n2; j++) sdp[0][j] = 1;
    for(int i=1; i<=len; i++)
    {
        for(int j=0; j<=n2; j++)
        {
            if(j>=m) {dp[i][j] = (sdp[i-1][j]-sdp[i-1][j-m]+P)%P;}
            else {dp[i][j] = sdp[i-1][j];}
            if((n2-j)%(m-1)==0 && i*(m-1)-j<=n1-1 && (n1-1-i*(m-1)+j)%(m-1)==0) {ans = (ans+dp[i][j]-dp[i-1][j]+P)%P;}
        }
        sdp[i][0] = dp[i][0]; for(int j=1; j<=n2; j++) sdp[i][j] = (sdp[i][j-1]+dp[i][j])%P;
    }
    printf("%lld\n",ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/suncongbo/p/11519281.html