日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Luogu P5469 [NOI2019]机器人 (DP、多项式)

發布時間:2025/3/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Luogu P5469 [NOI2019]机器人 (DP、多项式) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

不用FFT的多項式(大霧)

題目鏈接: https://www.luogu.org/problemnew/show/P5469

(這題在洛谷都成綠題了海星)

題解: 首先我們考慮,一個序列位置最右邊的最大值可以走遍整個序列,并且其余任何點都不能跨過這個位置。

所以我們可以區間dp, \(dp[l][r][x]\)表示區間\([l,r]\)最大值不超過\(x\)的方案數,枚舉最大值點\(mid\)及其值\(k\), \(dp[l][r][x]=\sum_{mid}\sum_{k}dp[l][mid-1][k]\times dp[mid+1][r][k-1]\), 也可以設\(dp[l][r][x]\)表示區間\([l,r]\)的最大值恰好為\(x\)的方案數,枚舉最大值點\(mid\)則有\(dp[l][r][x]=\sum_{mid}\sum_{k\le x}dp[l][mid-1][k]\sum_{k<x}dp[mid+1][r][k]\).

可獲得\(35\)分,當然如果你有夢想數組開大點卡卡常就有\(50\)分了。(然而我在考場上沒夢想\(35\)分滾粗了)

然后正解的話,恰好為\(x\)那種狀態比較好。

首先離散化,那么我們發現當\(k\)在每一段區間內時,轉移是類似的。

一個結論是,當\(k\)在某一段區間內時\(dp[l][r][k]\)是關于\(k\)的不超過\((r-l)\)次多項式。

證明: 首先\(l=r\)時顯然是\(0\)次多項式,當\(l<r\)時,我們枚舉\(mid\)然后左邊有一個\(mid-1-l\)次多項式右邊有一個\(r-mid-1\)次多項式,又因為轉移要對左右兩邊多項式做前綴和再相乘(這個具體見下一段),所以次數要\(+1\)(\(k\)次多項式的前綴和是\((k+1)\)次多項式),所以總次數為\((mid-1-l+1)+(r-mid-1+1)=r-l\).

這里解釋一下如何轉移: \(dp[l][r][x]\), 左右兩邊分開考慮,考慮現在枚舉的\(k\), 假設\(k\)\(x\)區間前面的區間里,那么這個值與\(x\)區間內的自變量無關了,變成了“常數”(因為這個區間所包含的數無論如何都比自變量小),而這個“常數”的值就是\(dp[l][r][k']\) (\(k'\)\(k\)所在的區間)這個多項式在每個\(k'\)區間內的點的點值之和,把這個值加到\(dp[l][r][x]\)多項式的常數項里。

假設\(k\)\(x\)區間里,那么新的多項式直接就等于這個多項式在區間內的小于等于自變量的前綴和(如果現在枚舉的是左邊),或者多項式在區間內小于自變量的前綴和(如果現在枚舉的是右邊)。

于是記憶化搜索一波,使用多項式前綴和進行轉移,這樣枚舉\(mid\)之后復雜度為多項式次數的平方。

多項式前綴和需要預處理\(s_k(x)=\sum^{x}_{i=0}x^k\), 這是一個\((k+1)\)次多項式,所以Lagrange插值求出來系數。據說有其他的搞法,但是我只能想到這一種。

裸做\(80\)分起步(我裸做了一波得了\(85\))

剪枝優化可獲得\(100\)分。

個人感覺這題部分分設置得真的特別合理,給出題人點贊!(我是認真的)

好難寫啊,我好菜啊……

代碼

#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<vector> #include<algorithm> #define llong long long using namespace std;const int P = 1e9+7; const int N = 301;llong quickpow(llong x,llong y) {llong cur = x,ret = 1ll;for(int i=0; y; i++){if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}cur = cur*cur%P;}return ret; } llong mulinv(llong x) {return quickpow(x,P-2);}llong aux[N+4],aux2[N+4]; struct Polynomial {vector<llong> a; int n;Polynomial() {}Polynomial(int _n) {n = _n; for(int i=0; i<=n; i++) a.push_back(0ll);}void clear() {n = 0; a.clear(); a.push_back(0ll);}void output() {printf("deg%d, ",n); for(int i=0; i<=n; i++) printf("%lld ",a[i]); puts("");}Polynomial operator +(Polynomial &arg) const{Polynomial ret(max(n,arg.n));for(int i=0; i<=min(n,arg.n); i++){ret.a[i] = (a[i]+arg.a[i])%P;}for(int i=min(n,arg.n)+1; i<=n; i++) ret.a[i] = a[i];for(int i=min(n,arg.n)+1; i<=arg.n; i++) ret.a[i] = arg.a[i];return ret;}Polynomial operator -(Polynomial &arg) const{Polynomial ret(max(n,arg.n));for(int i=0; i<=min(n,arg.n); i++){ret.a[i] = (a[i]-arg.a[i]+P)%P;}for(int i=min(n,arg.n)+1; i<=n; i++) ret.a[i] = a[i];for(int i=min(n,arg.n)+1; i<=arg.n; i++) ret.a[i] = P-arg.a[i];return ret;}Polynomial operator *(Polynomial &arg) const{Polynomial ret(n+arg.n);for(int i=0; i<=n; i++){for(int j=0; j<=arg.n; j++){ret.a[i+j] = (ret.a[i+j]+a[i]*arg.a[j])%P;}}return ret;}llong calc(llong x){llong ret = 0ll;for(int i=n; i>=0; i--){ret = (ret*x+a[i])%P;}return ret;}void interpoly(int _n,llong ax[],llong ay[]){n = _n; for(int i=0; i<=n; i++) a.push_back(0ll);for(int i=0; i<=n+1; i++) aux[i] = 0ll;aux[0] = 1ll;for(int i=0; i<=n; i++){for(int j=i+1; j>0; j--){aux[j] = (aux[j-1]-aux[j]*ax[i]%P+P)%P;}aux[0] = P-aux[0]*ax[i]%P;}for(int i=0; i<=n; i++){llong tmp = 1ll;for(int j=0; j<=n; j++){if(i==j) continue;tmp = tmp*(ax[i]-ax[j]+P)%P;}llong coe = mulinv(tmp);for(int j=n+1; j>=0; j--) {aux2[j] = aux[j];}for(int j=n; j>=0; j--){a[j] = (a[j]+aux2[j+1]*coe%P*ay[i])%P;aux2[j] = (aux2[j]+ax[i]*aux2[j+1])%P;}}} }; Polynomial tmp1,tmp2,tmp3; Polynomial dp[2661][(N<<1)+3],sdp[2661][(N<<1)+3]; llong lval[2661][(N<<1)+3],rval[2661][(N<<1)+3]; int dpid[N+4][N+4]; Polynomial spw[N+4]; struct Interval {llong lb,rb; //[1,2n] } a[N+3]; vector<llong> disc; llong spwx[N+3],spwy[N+3]; int mx[N+3][N+3]; int n,nsta; llong ans;int getid(llong x) {return lower_bound(disc.begin(),disc.end(),x)-disc.begin();} //no +1Polynomial prefixsum(Polynomial poly) {Polynomial ret(poly.n+1);for(int i=0; i<=poly.n; i++){for(int j=0; j<=i+1; j++){ret.a[j] = (ret.a[j]+poly.a[i]*spw[i].a[j])%P;}}return ret; }void dfs(int l,int r,int x) {Polynomial tmp1,tmp2,tmp3;if(dpid[l][r] && dp[dpid[l][r]][x].a.size()>0) {return;}if(!dpid[l][r]) {nsta++; dpid[l][r] = nsta;}if(l==r){if(!dpid[l][r]) {nsta++; dpid[l][r] = nsta;}dp[dpid[l][r]][x] = Polynomial(0); dp[dpid[l][r]][x].a[0] = (x>=a[l].lb&&x<=a[l].rb) ? 1ll : 0ll;sdp[dpid[l][r]][x] = prefixsum(dp[dpid[l][r]][x]);lval[dpid[l][r]][x] = sdp[dpid[l][r]][x].calc(disc[x-1]);rval[dpid[l][r]][x] = sdp[dpid[l][r]][x].calc(disc[x]);return;}dp[dpid[l][r]][x].clear(); sdp[dpid[l][r]][x].clear();if(mx[l][r]>x) return;for(int lenl=(r-l+1)>>1; lenl<=(r-l+1)+1-((r-l+1)>>1); lenl++){int mid = l+lenl-1;if(!(x>=a[mid].lb && x<=a[mid].rb)) {continue;} //注意此處要特判tmp1.clear(); tmp2.clear();if(mid>l){for(int k=1; k<=x; k++){dfs(l,mid-1,k);if(k<x){tmp1.a[0] = (tmp1.a[0]+rval[dpid[l][mid-1]][k]-lval[dpid[l][mid-1]][k]+P)%P;}else{tmp1 = tmp1+sdp[dpid[l][mid-1]][k];tmp1.a[0] = (tmp1.a[0]-lval[dpid[l][mid-1]][k]+P)%P;}}}else{tmp1 = Polynomial(0); tmp1.a[0] = 1ll;}if(mid<r){for(int k=0; k<=x; k++){dfs(mid+1,r,k);if(k<x){tmp2.a[0] = (tmp2.a[0]+rval[dpid[mid+1][r]][k]-lval[dpid[mid+1][r]][k]+P)%P;}else{tmp2 = tmp2+sdp[dpid[mid+1][r]][k];tmp2 = tmp2-dp[dpid[mid+1][r]][k];tmp2.a[0] = (tmp2.a[0]-lval[dpid[mid+1][r]][k]+P)%P;}}}else{tmp2 = Polynomial(0); tmp2.a[0] = 1ll;}tmp3 = tmp1*tmp2;dp[dpid[l][r]][x] = dp[dpid[l][r]][x]+tmp3;}sdp[dpid[l][r]][x] = prefixsum(dp[dpid[l][r]][x]);lval[dpid[l][r]][x] = sdp[dpid[l][r]][x].calc(disc[x-1]);rval[dpid[l][r]][x] = sdp[dpid[l][r]][x].calc(disc[x]); }int main() {scanf("%d",&n);for(int i=1; i<=n; i++) {scanf("%lld%lld",&a[i].lb,&a[i].rb); disc.push_back(a[i].lb-1); disc.push_back(a[i].rb);}for(int i=0; i<=n; i++){spwx[0] = 0ll; spwy[0] = 0ll;for(int j=1; j<=i+1; j++){spwx[j] = j;spwy[j] = (spwy[j-1]+quickpow(j,i))%P;}spw[i].interpoly(i+1,spwx,spwy);}sort(disc.begin(),disc.end()); disc.erase(unique(disc.begin(),disc.end()),disc.end());for(int i=1; i<=n; i++) {a[i].lb = getid(a[i].lb); a[i].rb = getid(a[i].rb);}nsta = 1; for(int i=0; i<disc.size(); i++){dp[1][i] = Polynomial(0); dp[1][i].a[0] = 1ll;sdp[1][i] = prefixsum(dp[1][i]);lval[1][i] = sdp[1][i].calc(disc[i-1]);rval[1][i] = sdp[1][i].calc(disc[i]);}for(int i=1; i<=n; i++){mx[i][i] = a[i].lb;for(int j=i+1; j<=n; j++){mx[i][j] = max(mx[i][j-1],(int)a[j].lb);}}ans = 0ll;for(int i=1; i<disc.size(); i++){dfs(1,n,i);ans = (ans+sdp[dpid[1][n]][i].calc(disc[i])-sdp[dpid[1][n]][i].calc(disc[i-1])+P)%P;}printf("%lld\n",ans);return 0; } 與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的Luogu P5469 [NOI2019]机器人 (DP、多项式)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。