BZOJ 3157 3516 4126 國王奇遇記

2022-03-31 14:18:14 字數 3798 閱讀 9852

目錄題目傳送門1

題目傳送門2

題目傳送門3

計算\(\sum_^i^m*m^i\)

\(\%\)

\(10^9+7\)

\((1 \leq n \leq 10^9)\)

bzoj3157:\(1 \leq m \leq 200\)

bzoj3516:\(1 \leq m \leq 1000\)

bzoj4126:\(1 \leq m \leq 50000\)

一般題目短的都很毒這道題各種做法都有,想不想的出來似乎只有看推式子的能力了。推不出式子的話那就只能亂搞了。先講一種自己單獨想出來的但是複雜度**的做法,複雜度似乎是\(o(m^3log(n))\)的,然而似乎可以過。。首先我們把這個式子用拆成這樣:\(\sum_^i^m*m^i=m*(1^m+m(2^m+m(...m(n^m))))\),然後可以發現這個式子是非常有規律的,於是我們就考慮矩乘,但這個\(i^m\)非常的難弄,所以我們在矩陣中同時記錄這個\(i^m\),然後一起轉移就行了,然而這個看起來非常好寫的做法複雜度很高,然而**也調了好久(感覺自己蒿菜啊~),所以**就不放了2333。

然後開始講一下比較高階的做法。。首先是\(o(m^2log(n))\)的做法,我們記\(f(n,k)=\sum_^i^k*m^i\),那麼:

\[\begin

& f(n+1,k) &= \sum_^i^k*m^i \\

&=\sum_^i^k*m^i+m \\

&=\sum_^(i+1)^k*m^+m \\

&=\sum_^m^\sum_^kc_k^j*i^j+m \\

&=\sum_^c_k^j*m\sum_^ni^j*m^i+m \\

&=\sum_^kc_k^j*m*f(n,j)+m

\end

\]這樣我們就可以用\(o(m^2)\)的時間從\(n\)轉移到\(n+1\)。我們繼續:

\[\begin

& f(2n,k) &= \sum_^i^k*m^i \\

&= \sum_^i^k*m^i+\sum_^i^k*m^i \\

&= f(n,k)+\sum_^(i+n)^k*m^ \\

&= f(n,k)+\sum_^m^\sum_^c_k^j*i^j*n^ \\

&= f(n,k)+\sum_^c_k^j*n^*m^n\sum_^i^j*m^i \\

&= f(n,k)+m^n\sum_^c_k^j*n^*f(n,j)

\end

\]這樣我們就可以同樣用\(o(m^2)\)的時間從\(n\)轉移到\(2n\)。接下來就是比較簡單的遞迴處理了,總複雜度為\(o(m^2log(n))\)。

#include using namespace std;

typedef long long ll;

bool finish_read;

templateinline void read(t &x)while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;finish_read=1;}

templateinline void print(t x)

templateinline void writeln(t x)

templateinline void write(t x)

/****************=header template**********====*/

#define pause printf("press enter key to continue..."); fgetc(stdin);

const int md=1e9+7;

const int n=205;

ll n;

int m;

ll c[n][n],f[n][n];

/****************===define area***************=*/

ll powe(ll x,ll y)

return res;

}void init() }}

void calc(ll x,int y)

return ;

} if(x&1)

(f[y][i]*=m)%=md;(f[y][i]+=m)%=md;

} }else

(f[y][i]*=pw)%=md;

(f[y][i]+=f[y+1][i])%=md;

} }}int main()

然而這麼高階的做法過不去bzoj3516,畢竟老年機於是我們思考更加優越的做法,我們發現上面乙個做法實際上可以用一維記錄,因為\(n\)只能轉移到\(n+1\)或者\(2n\),這樣我們就需要思考是否可以省去\(n\)這一維。於是我們記\(f(k)=\sum_^ni^k+m^i\)

那麼:\[\begin

& (m-1)*f(k) &= (m-1)*\sum_^i^k*m^i \\

&= \sum_^ni^k*m^ -\sum_^ni^k*m^i \\

&= \sum_^(i-1)^k*m^i-\sum_^ni^k*m^i \\

&= \sum_^((i-1)^k-i^k)*m^i+n^km^ \\

&= \sum_^m^i\sum_^c_k^j*(-1)^*i^j+n^km^ \\

&= \sum_^c_k^j*(-1)^*\sum_^i^j*m^i+n^km^ \\

&= \sum_^c_k^j*(-1)^*f(j)+n^km^

\end

\]於是我們可以得出\(f(k)=\frac^c_k^j*(-1)^*f(j)+n^km^}\)。這樣我們就得到了\(o(m^2)\)的做法,就可以過bzoj3516的資料範圍了。

#include using namespace std;

typedef long long ll;

bool finish_read;

templateinline void read(t &x)while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;finish_read=1;}

templateinline void print(t x)

templateinline void writeln(t x)

templateinline void write(t x)

/****************=header template**********====*/

#define pause printf("press enter key to continue..."); fgetc(stdin);

const ll md=1e9+7;

const int n=2005;

int n,m;

ll c[n][n],f[n];

/****************===define area***************=*/

void init() }}

ll powe(ll x,int y)

return res;

}int main() {

read(n);read(m);

init();

if(m==1) return printf("%lld\n",((ll)(n+1)*n/2)%md),0;

ll sum=powe(m,n+1);

f[0]=(sum-m+md)%md;

ll div=powe(m-1,md-2);f[0]*=div;f[0]%=md;

for(int i=1;i<=m;i++) {

sum*=n;sum%=md;f[i]=sum;

for(int j=0;j然後。。\(o(m)\)的高階演算法。。留個坑,奶一口肯定能夠填回來。

BZOJ1052 BZOJ3760 覆蓋問題

原題位址 先說自己的逗比方法 二分答案,把所有點用乙個最小的矩形 框 起來,易證矩形的其中乙個端點是最優解中正方形的乙個端點,然後列舉四個端點後遞迴處理,差不多了 然後 olz黃學長的o n 做法 ac code include include include using namespace std...

動態點分治 bzoj 3730,bzoj 1095

總結一下動態點分治的模板。對於乙個樹,把它點分的同時記錄每個點的所有父親 logn個 並記錄點距其父親的距離。具體實現就是dfs的時候fa x dep x u,dis x dep x d bzoj1095 您需要寫乙個程式支援反轉點的顏色,求距離最遠的黑色點對的距離。解析 在每個點u存乙個堆st記錄...

福慧雙修 探險 BZOJ4398 BZOJ2407

分析 雙倍經驗 資料範圍不同 我們考慮,我們必定是從1走一條邊到節點i,之後從i到j跑最短路,之後再從j到1走另一條邊的情況下,不會重複,並且是答案。那麼我們考慮預處理出pre i 表示從1走到i滿足最短路的並且經過pre i pre i 為路徑第二個節點。那麼,針對每乙個邊,x,y,z,v 滿足當...