天天看點

Codeforces 1506F - Triangular Paths

Codeforces Round #710 (Div. 3) F. Triangular Paths

題意

有一個無限高度的三角形,頂端編号為\((1,1)\),第\(r\)層有\(r\)個點,從左至右按順序\(c\)編号為\((r,c)\),如圖所示

Codeforces 1506F - Triangular Paths

對于每個節點\((r,c)\),都有兩條連接配接下一層相鄰節點\((r+1,c),(r+1,c+1)\)的單向邊,但這兩條邊在同一時間隻有一條是有效邊,且隻有有效邊能夠通過

初始時,如果\(r+c\)是偶數,那麼\((r,c)\rightarrow (r+1,c)\)是有效邊;如果是奇數,那麼\((r,c)\rightarrow (r+1,c+1)\)是有效邊

你可以改變從某個點出發的有效邊(若原來指向左邊則現在指向右邊,反之指向左邊),這需要産生花費\(1\)

現給定\(n\)個點,保證在不考慮有效邊的前提下,一定存在一條單向路徑能夠同時通過這\(n\)個點

問如果按任意順序經過全部\(n\)個點,最小花費是多少

限制

\(1\le T\le 10^4\)

\(1\le n\le 2\cdot 10^5\)

\(1\le r_i\le 10^9\)

\(1\le c_i\le r_i\)

\(\sum n\le 2\cdot 10^5\)

思路

淦讀錯題了,是道水題,又是差點ak的一次。。。

由于這是一個單向圖,且根據題意,每走過一條邊行數一定會增加\(1\)

又因為保證在不考慮有效邊的前提下,一定存在一條單向路徑能夠同時通過這\(n\)個點,是以每個點的經過順序一定是确定的

是以按照層數對\(n\)個點進行排序,然後按順序處理即可

根據題意的初始有效邊分布,可繪出下圖

Codeforces 1506F - Triangular Paths

因為一定存在一條路徑

往左下走會使得\(r-c\)值\(+1\),\(c\)值不變

往右下走則會使得\(c\)值\(+1\),\(r-c\)值不變

是以可以得到:每個經過的點的\(c\)與\(r-c\)值一定是非遞減的

于是可以分類讨論“上一點”與“下一點”之間的關系來計算答案

  • 假如“上一點\((r_a,c_a)\)”與“下一點\((r_b,c_b)\)”的\(r-c\)值相同

說明路徑隻有可能是全部按照\((r,c)\rightarrow (r+1,c+1)\)進行移動

那麼讨論\(r-c\)的奇偶性:

如果\(r-c\)為奇數,那麼在初始圖中兩點間剛好全是有效邊,不需要産生任何花費

如果\(r-c\)為偶數,那麼沒有路徑上沒有任何一條邊是有效邊,将會産生\(c_b-c_a\)的花費

  • 假如“上一點\((r_a,c_a)\)”與“下一點\((r_b,c_b)\)”的\(r-c\)值不同

這裡可以将\(\lfloor\frac{r-c}2\rfloor\)值相同的所有點看作一組,那麼産生的花費就是這兩個點跨越的組的數量

如果上一點的\(r_a-c_a\)值為偶數,則花費增加\(\lfloor\frac{\Delta (r-c)}2\rfloor\)

如果上一點的\(r_a-c_a\)值為奇數,則花費增加\(\lfloor\frac{\Delta (r-c)+1}2\rfloor\)

代碼

(109ms/2000ms)

#include<bits/stdc++.h>
using namespace std;

struct node
{
    int r,c,d;
    bool operator < (const node& a)
    {
        return r<a.r;
    }
}ar[200050];

void solve()
{
    int n;
    cin>>n;
    
    ar[0]={1,1,0};
    for(int i=1;i<=n;i++)
        cin>>ar[i].r;
    for(int i=1;i<=n;i++)
    {
        cin>>ar[i].c;
        ar[i].d=ar[i].r-ar[i].c;
    }
    
    sort(ar+1,ar+1+n);
    
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(ar[i].d==ar[i-1].d)
        {
            if(ar[i].d%2==0)
                ans+=ar[i].c-ar[i-1].c;
        }
        else
        {
            if(ar[i-1].d%2==0)
                ans+=(ar[i].d-ar[i-1].d)/2;
            else
                ans+=(ar[i].d-ar[i-1].d+1)/2;
        }
    }
    cout<<ans<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;while(T--)
        solve();
    return 0;
}
           

https://blog.csdn.net/qq_36394234/article/details/115223089