Luogu-P3205-HNOI2010-合唱队
題目地址
思路
這道題其實是P3146 [USACO16OPEN]248的升級版,但是N的范圍很大,為262144。原先的O(N^3)的方法自然會TLE,甚至O(N^2)的方法也不足以解決。
定義f[i][j]為從左端點j開始,能合并出i的(右端點值+1)的值
首先進行初始化,對于坐標為i點的值t,處理如下:
他的左斷點為i,能合并出的值為t,右端點為i,值賦予i+1
為什么是i+1呢?因為我們之后合并兩個數的時候,從f[i][j]去搜,可以直接將其作為左端點搜索下一個數。
轉移方程為:
\[f[i][j]=f[i-1][f[i-1][j]]\]
為什么?
\(f[i-1][j]\)代表從端點j開始找能合并成i-1的最少距離,并找出右端點的下一個端點。
\(f[i-1][f[i-1][j]]\)就代表從上一個找到的右端點下個端點開始搜索。如果沒有搜到,肯定返回時0,就說明沒有找到。
所以,如果當\(f[i][j]\)不為0后,這個i就是最大合并的值。
所以我們只要枚舉i與j就可以了。
j的范圍是n,那i呢?
我們知道,數最大是40,兩個40合成一個41,四個40合成一個42,八個40合成一個43,十六個40合成一個44。
假設數都是最大的40,可以得出2^x個數字可以合成最大的值為40+x。
又因為N=262144,而且2^18=262144,所以最大的合成數為40+18=58,我們只要枚舉到58就行了。
代碼示例
#include<cstdio> using namespace std; int f[61][262145],n,x,ans; int main(){scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&x),f[x][i]=i+1;for(int i=2;i<=58;i++){for(int j=1;j<=n;j++){if(!f[i][j])f[i][j]=f[i-1][f[i-1][j]];if(f[i][j])ans=i;}}printf("%d",ans);return 0; }PS:當然,把數組開反也是可以的。
轉載于:https://www.cnblogs.com/dmoransky/p/10742631.html
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的Luogu-P3205-HNOI2010-合唱队的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自定义用户环境
- 下一篇: Spring AOP capabilit