3.24模拟
前言
期望:100+20+68=188
實際:100+12+32=144
rnk4。
三高一碾壓五高二。
TLE掛了28分,失誤掛了16分。
繼前天的CF比賽之后再次分塊TLE而FST…
本機T3那28分得跑3.3-3.4s左右,但是由于本機比較老了,啟動運行似乎有一定時間,跑個樣例動不動都跑個0.8s-1s,所以覺得實測應該是可過的。(更何況我這個復雜度Solution都提到了可以拿68)
然而現實很骨感…(為什么KH的機子不是太湖之光啊)
失誤如下:
解析
T1
確實是送分題,水到即使切掉也完全感覺不到安全感那種。
我的構造方法是構造一堆長度為2的鏈,然后如果整除不了就找個葉子當菊花花心接著構造,極限數據大概是220個點左右。
題解的構造上限也太驚人了些…思路倒是挺顯然,但是不明白怎么把路徑恰好用完的…
可能需要億些分類討論吧。那還不如我這個好寫
T2
很巧妙的題。
大佬們都用SAM切掉了,只有我覺得是SA然后咋也不會…
(說句閑話,這個題是怎么想到用SAM的啊…題意難道不和SA更配嗎?qwq)
正解還真是SA…
分治。
講完了。
然后思路就很自然了,遞歸找到當前區間最小的 height\text{height}height,然后往兩邊遞歸計算,最后求出一個 xxx 使得兩邊的最大值相等即可。
正解很好寫,補起來身心愉悅。
之前明明總結過,這次還是想不起來…分治這種東西可能很難自然的想到(至少對我而言),需要刻意的去往這方面想一想。
T3
兩小時大分塊比暴力多12分,樂。
我的做法和題解本質上差不多,我預處理的那個“轉移系數”其實就是題解的轉移矩陣。
這題一開始我倒是想到矩乘了,但是一想到 m3m^3m3 的單次乘法復雜度我直接放棄…
題解一句輕描淡寫“預處理出前綴和后綴的轉移矩陣即可,時間復雜度 O(nm2)O(nm^2)O(nm2)”。
你給我開兩個 nm2nm^2nm2 的數組試試!
可能還是我沒理解題解的做法吧…
那先講講我的吧。
先考慮暴力dp怎么做。
令 gig_igi? 表示以 iii 結尾的之前沒有出現過的子序列個數。
每次對于第 iii 個位置,設 aia_iai? 上一次出現位置是 preprepre,則 gi=∑j=prei?1gjg_i=\sum_{j=pre}^{i-1}g_jgi?=∑j=prei?1?gj?。
然后前綴和優化一些就 O(nq)O(nq)O(nq) 了。
這個東西轉化一下就變成:
有兩個數組 ansi,fians_i,f_iansi?,fi?, 注意這里iii的是一個字符而不是位置 ,每次添加一個字符 ccc,就令 fi←fc(i≠c),ansc←fcf_i\gets f_c(i\ne c),ans_c\gets f_cfi?←fc?(i?=c),ansc?←fc?。
然后發現這個東西的轉移過程十分固定,但是矩乘又存不下所有的矩陣,怎么辦呢?
考慮分塊。
設塊長為 BBB ,考慮都有哪些復雜度。
由于矩乘復雜度太高,我們不再存矩陣,而是存對于每一個 iii,初始時的 fi=1f_i=1fi?=1 能轉移到的 ansj,fjans_j,f_jansj?,fj? 的系數 transansi,j,transfi,jtransans_{i,j},transf_{i,j}transansi,j?,transfi,j?。
前綴計算非常舒適,枚舉 iii,正著推一遍到塊的結尾記錄即可。復雜度 O(m(n+nBm))O(m(n+\dfrac{n}{B}m))O(m(n+Bn?m))。(前面的 mmm 是枚舉的 iii,后面是記錄的復雜度)
后綴計算比較難受,由于我們的遞推并不能倒著推,我們只能對于每一個塊的起始都重新暴力推一遍(我沒有想到題解那個奧妙重重的右乘矩陣),但好在我們推到這一塊的結尾的時候就可以利用后面一塊已經算好的轉移系數直接轉移到最后(這個過程其實就是行矩陣乘轉移矩陣,復雜度 O(m2)O(m^2)O(m2)),因此總復雜度是 O(mnB(B+m2))O(m\dfrac{n}{B}(B+m^2))O(mBn?(B+m2))。
然后考慮回答詢問,我們需要暴力轉移散點(這個可以通過和題解類似的對全局記錄 fff 的累加和然后記錄每個 fif_ifi? 相應減去的 tagitag_itagi? 做到 O(len+m)O(len+m)O(len+m)),復雜度為 O(qB)O(qB)O(qB),整塊的轉移系數我們直接用就可以。
平衡一下令 B=m1.5B=m^{1.5}B=m1.5 復雜度達到最優,總復雜度 O((n+q)m1.5)O((n+q)m^{1.5})O((n+q)m1.5)。
(我本來以為這復雜度直接能切了,寫完才發現我忽略了利用轉移系數轉移就需要 O(m2)O(m^2)O(m2) 的時間,所以至少是 O(qm2)O(qm^2)O(qm2) 的…但 68 都過不去是我沒想到的)
現在講講我對題解閱讀理解的心得。
題解的dp和我的本質相同,然后把 ans,fans,fans,f 擺成一個行向量,每次就相當于乘一個轉移矩陣。
這個矩陣差不多長這樣:
(m=4,c=2)
然后乘完確實是它說的那樣。
上面的第三個矩陣是一*二的結果。類似于 m+3=7m+3=7m+3=7 列的值加給了其他列。
上面的第三個矩陣是二*一的結果。類似于 m+3=7m+3=7m+3=7 行吸收了其他行。
但是知道了這個我還是不會。
提供這個現象,等待高人指點。
qwq
生成矩陣的代碼:
#include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define debug(...) fprintf(stderr,__VA_ARGS__) #define ok debug("OK\n") using namespace std;const int N=200+100; const int C=205; const int mod=998244353;inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f; }int n,m; struct matrix{int x,y;ll a[C<<1][C<<1];matrix(int c,int d){x=c;y=d;memset(a,0,sizeof(a));}matrix(){memset(a,0,sizeof(a));}void make(int c){x=y=m+m;memset(a,0,sizeof(a));for(int i=1;i<=m+m;i++) a[i][i]=1;//a[m+c][m+c]=0;for(int i=1;i<=m;i++){//if(i!=c) a[m+c][m+i]=1;}a[m+c][c]=1;}void print(){printf("\nprint: ---\n");for(int i=1;i<=x;i++){for(int j=1;j<=y;j++) printf("%lld ",a[i][j]);puts("");}return;} }; matrix operator * (const matrix &u,const matrix &v){matrix res(u.x,v.y);for(int k=1;k<=u.y;k++){for(int i=1;i<=u.x;i++){ll tmp=u.a[i][k];for(int j=1;j<=v.y;j++){(res.a[i][j]+=tmp*v.a[k][j])%=mod;}}}return res; } int a[N]; matrix pre[N],suf[N]; signed main(){freopen("a.in","r",stdin);freopen("a.out","w",stdout);n=read();m=read();int ask=read();for(int i=1;i<=n;i++) a[i]=read();pre[0].x=pre[0].y=m+m;for(int i=1;i<=m+m;i++) pre[0].a[i][i]=1;for(int i=1;i<=n;i++){//printf("\n----------a=%d\n",a[i]);matrix o(m+m,m+m);o.make(a[i]);o.print();pre[i]=pre[i-1]*o;pre[i].print();}printf("---------------------------------------------------------------\n");suf[n+1].x=suf[n+1].y=m+m;for(int i=1;i<=m+m;i++) suf[n+1].a[i][i]=1;for(int i=n;i>=1;i--){printf("\n----------a=%d\n",a[i]);matrix o(m+m,m+m);o.make(a[i]);o.print();suf[i]=o*suf[i+1];suf[i].print();}matrix ori;ori.x=1;ori.y=m+m;for(int i=m+1;i<=m+m;i++) ori.a[1][i]=1;while(ask--){int pl=read(),add=read(),d=read();matrix res;res.make(add);res=res*suf[pl+1];res=res*pre[pl-1];//res.print();res=ori*res;printf("%lld\n",res.a[1][d]);}return 0; } /* */總結
- 上一篇: 设计师用的电脑配置(设计的电脑要什么配置
- 下一篇: 模板:LGV引理(线性代数)