CF559E Gerald and Path

cf

兩回啊兩回...

不妨先將所有線段按照端點從小到大排序,並假設只能往右放,然後強行套上一個dp\(f_{i,j}\)表示放完前\(i\)個線段,最右覆蓋到\(j\)的答案,轉移時枚舉下一條放進來的線段,因爲現在是隻往右放,所以只能去覆蓋\(j\)以後的部分,轉移\(f_{i,j}+min(a_k+l_k-j,l_k)\to f_{k,\max(a_k+l_k,j)}\)

然後這題裏面現在是可以往左放的.如果當前線段往右放,那麼因爲放過的線段都在它的前面,所以它覆蓋的一定是當前的最右端\(j\)以後的位置.但是如果往左放,可能會出現覆蓋的新段有多個段的問題.爲了避免這種情況,因爲前面我們是枚舉在\(i\)後面的一個線段\(k\),那麼先不考慮\(i,k\)之間的線段,只考慮\(k\)覆蓋左邊以及前面覆蓋最右端\(j\)的影響,這裏貢獻爲\(min(a_k-j,l_k)\).然後對於\(i,k\)之間的線段,我們將他們全部向右放,並考慮貢獻,如果這一些線段最右端爲\(mx\),那麼這裏貢獻爲\(mx-a_k\)

至於爲什麼這樣子是對的,首先可以發現這樣子轉移貢獻一定不會算多,因爲每次覆蓋的地方都是之前沒覆蓋過的地方;然後注意到\(k\)往左放的時候,可能到達的最左端點比當前\(i\)的左端點還要左,但並沒有考慮\(i\)左端點以左的部分,那如果出現這種情況,其實\(i\)左端點以左的貢獻可以在\(i\)前面的位置\(i'\)被統計,而在\(i'\)\(i\)也就是有一個往右貢獻;至於在\(i'\)處轉移時\(i\)往左更優怎麼辦,那就會先統計\(i\)往左的貢獻,然後在\(i\)處轉移是統計\(k\)的貢獻,因爲\(i\)往左更優,說明\(k\)往左不會蓋到\(i\)線段左端點

形式化的,下面的狀態爲\(f_{i,j,k(0/1)}\)表示前\(i\)個線段,覆蓋到最右端的線段爲\(j\),方向朝左/朝右,這樣我們可以把某條線段\(x\)的右端點表示爲\(a_x+k*l_x\).然後轉移的時候記錄枚舉過的線段的最右的\(j,k\),記爲\(nj,nk\),然後當前枚舉線段\(x\)方向\(p\),轉移可以寫成

\(f_{i,j,k}+min((a_{x}+p*l_{x})-(a_{j}+k*l_{j}),l_x)+(a_{nj}+nk*l_{nj})-(a_{x}+p*l_{x})\to f_{x,nj,nk}\)

#include<bits/stdc++.h>
#define LL long long
#define db double

using namespace std;
const int N=100+10,M=205,mod=1e9+7;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
struct node
{
    int x,y;
    bool operator < (const node &bb) const {return x<bb.x;}
}a[N];
int n,f[N][N][2];
int ps(int x,int y){return a[x].x+a[x].y*y;}

int main()
{
    n=rd();
    for(int i=1;i<=n;++i) a[i].x=rd(),a[i].y=rd();
    a[++n]=(node){-(int)2e8,0};
    sort(a+1,a+n+1);
    memset(f,-0x3f3f3f,sizeof(f));
    f[1][1][0]=0;
    int ans=0;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=i;++j)
            for(int k=0;k<=1;++k)
            {
                ans=max(ans,f[i][j][k]);
                int nj=j,nk=k;
                for(int l=i+1;l<=n;++l)
                    for(int p=0;p<=1;++p)
                    {
                        if(ps(nj,nk)<=ps(l,p)) nj=l,nk=p;
                        f[l][nj][nk]=max(f[l][nj][nk],f[i][j][k]+min(ps(l,p)-ps(j,k),a[l].y)+ps(nj,nk)-ps(l,p));
                    }
            }
    printf("%d\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章