恰好是去年的這個時候左右,我做了這個系列的前兩題。。(其實相當於只做了一題hhh)然而當時的姿勢水平非常低,式子大概都是瞎jb湊出來的。。。(也有可能看了波題解?)反正到了第三題就徹底一臉懵逼了。。記得看題解也看不懂是個毛。。後來就棄了。。
一年之後的現在。。。前幾天dwj老司機誤以爲我做過這個題(的再加強版)。。於是就來問我怎麼證答案是用一個多項式來表示的。。。我想我好像都看(翻)完了具體數學求和的那幾章。。不如就來肛一波這個題啊。。。於是總共花了差不多三天,總時長大概5h+。。期間把我學過的不少組合數學的東西都搞過了。。獨立艹掉了這個題真是感動QAQ。。。然而感覺現在的姿勢水平還是好低啊。。(最後還是有一點同學的幫助hhhhh)
進入正題啦。
給定一個與
比較套路的搞法是,因爲
可以看到後面那坨東西和一開始要算的東西形式類似,於是記
注意將
稍微移一下項可得
至此,我們得到了一個
接下來就不是那麼自然了,但也是可以想到的。
注意到
因此我們先假設
則
對比係數得
注意到
其中
然而知道這個有什麼卵用呢???
如果我們將多項式換個表示方法,就會有神效。對於多項式
(實際上牛頓級數只用求和到
這實際上是
我們再將
這意味着,知道
(解鎖成就:獨立推出
UPD:原來這玩意就是傳說中的“線性插值”啊。。。23333333
接下來就是算
我們來重新定義一下,設答案爲
對
也就是
這樣可以遞推出
其實這一步就簡單的了。。。考慮對
這個時候前面一半就是對
接着利用前面的那個求值方法就可以算出
這樣就結束了。。。?
我們來看一下複雜度。。。全程看起來指標都是
。。。嗎?
仔細看看會發現算
不管啦直接肛
結果第一次交大常數版本的時候TLE了
瞎改了點東西這破
然後經同學提醒。。。這玩意是積性的啊。。。不是可以直接篩麼???
[捂臉熊.jpg]
於是就輕易地
完結撒花!
【一些東西】
不太會寫腳註就在這裏把中間用過的一些《具體數學》[人民郵電出版社,第二版]上的結論一次性列出來吧。
牛頓級數:P157,沒有標成公式,畢竟只是多項式的一種表示形式吧。
二項式反演:用了P160,(5.48)的另一種形式
初始的式子還可以用分部求和搞出來,P234,(6.69)。
【主要代碼】
int n , m;
arr fact , invF , pw;
arr F , c2 , pwk;
void input() {
n = rd() , m = rd();
}
inline void init() {
m ++;
fact[0] = invF[0] = 1;
rep (i , 1 , m) fact[i] = mul(fact[i - 1] , i);
invF[m] = Pow(fact[m] , mod - 2);
per (i , m , 1) invF[i - 1] = mul(invF[i] , i);
pw[0] = 1;
m --;
rep (i , 1 , m + 1) pw[i] = mul(pw[i - 1] , m);
static arr vis , pr;
int tot = 0;
pwk[1] = 1;
rep (i , 2 , m + 1) {
if (!vis[i])
pr[++ tot] = i , pwk[i] = Pow(i , m);
rep (j , 1 , tot) if (i * pr[j] > m + 1) break; else {
vis[i * pr[j]] = 1;
pwk[i * pr[j]] = mul(pwk[i] , pwk[pr[j]]);
if (i % pr[j] == 0) break;
}
}
}
inline int _C(int n , int m) {
return n >= m ? mul(fact[n] , mul(invF[m] , invF[n - m])) : 0;
}
inline void get_F0() {
int invm = Pow(m , mod - 2) , mm = 1;
int up = 0 , down = 0;
int S = 0;
rep (k , 0 , m + 1) {
int tmp = _C(m + 1 , k);
if ((m + 1 - k) & 1) tmp = mod - tmp;
tmp = mul(tmp , mm);
up = add(up , mul(tmp , S));
down = add(down , tmp);
mm = mul(mm , invm);
S = add(S , mul(pw[k] , pwk[k]));
}
up = mod - up;
F[0] = mul(up , Pow(down , mod - 2));
}
inline void calc_F() {
int invm = Pow(m , mod - 2);
rep (k , 1 , m + 1) {
F[k] = add(pwk[k - 1] , F[k - 1]);
F[k] = mul(F[k] , invm);
}
}
inline int binom(int n , int m) {
int t = invF[m];
For (i , 0 , m)
t = mul(t , n - i);
return t;
}
inline int inv(int i) {
return mul(fact[i - 1] , invF[i]);
}
inline void calc_ans() {
int ans = 0;
int c1 = 1;
c2[m] = 1;
Dwn (j , m , 0) c2[j] = mul(c2[j + 1] , mul(n - j - 1 , inv(m - j)));
rep (j , 0 , m) {
if (j)
c1 = mul(c1 , mul(n - j + 1 , inv(j)));
int tmp = mul(c1 , F[j]);
tmp = mul(tmp , c2[j]);
if ((m - j) & 1) tmp = mod - tmp;
ans = add(ans , tmp);
}
ans = mul(Pow(m , n) , ans);
ans = dec(ans , F[0]);
printf("%d\n" , ans);
}
void solve() {
if (m == 1) {
int ans = 1ll * n * (n + 1) / 2 % mod;
printf("%d\n" , ans);
return;
}
if (n <= m) {
int ans = 0;
int t = m;
rep (i , 1 , n)
ans = add(ans , mul(t , Pow(i , m))) , t = mul(t , m);
printf("%d\n" , ans);
return;
}
n ++;
init();
get_F0();
calc_F();
calc_ans();
}