1. 程式人生 > 其它 >USACO 2018 Feb 題解

USACO 2018 Feb 題解

USACO 2018 Feb Solution

目錄

更好的閱讀體驗戳此進入

題面 Luogu 連結

LG-P4266 [USACO18FEB]Rest Stops S

題面

這題你們基本都讀完就能切吧。。真的很水。。

sssmzy 和他的私人教練 zpair 正在徒步攀爬彩虹糖山,我們將其抽象成一條長度為 $ l $ 的長直路徑,其中有 $ n $ 個彩虹糖補給站,每個有 $ x_i, c_i $ 分別表示距離 $ 0 $(也就是起點)點的距離和每秒能吃到的彩虹糖數量。sssmzy 會以 $ r_f\texttt{秒/米} $(你沒看錯)的速度一直前進,zpair 的速度是 $ r_b\texttt{秒/米} $,同時可以選擇在某個補給站休息任意秒吃掉對應數量的彩虹糖,因為 zpair 比較年輕,所以保證 $ r_b \lt r_f $,但是因為年輕人比較有活力,所以他必須全程都不在 sssmzy 後面,求 zpair 最多可以吃到多少彩虹糖。

$ 1 \le l \le 10^6, 1 \le n \le 10^5, 1 \le r_b \lt r_f \le 10^6, 1 \le c_i \le 10^6, 0 \lt x_i \lt l $。

$ l, n, r_f, r_b $

$ x_1, c_1 $

$ x_2, c_2 $

$ \cdots $

$ x_n, c_n $

Examples

Input_1

10 2 4 3
7 2
8 1

Output_1

15

Solution

沒啥可說的吧?按照 $ c_i $ 排個序,無腦優先選可以選的最高價值的補給站,模擬一下即可,記得開 long long,這個貪心我感覺沒有綠色的難度。。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template< typename T = int >
inline T read(void);

int L, N;
vector < pair < int, int >/*price, position*/ > rest;
int spdF, spdB;
int d;
ll ans(0);

int main(){
    L = read(), N = read(), spdF = read(), spdB = read(); d = spdF - spdB;
    for(int i = 1; i <= N; ++i){int p = read(), c = read(); rest.emplace_back(c, p);}
    int cur(0); sort(rest.begin(), rest.end(), greater < pair < int, int > >());
    for(auto res : rest)
        ans += (ll)res.first * max(0, res.second - cur) * d, cur = max(cur, res.second);
    printf("%lld\n", ans);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

LG-P4264 [USACO18FEB]Teleportation S

題面

數軸上存在 $ n $ 對 $ a_i, b_i $ 表示有一坨牛糞需要從 $ a_i $ 送到 $ b_i $ 並貢獻 $ d_i = \vert a_i - b_i \vert $,數軸上存在一個起點為 $ 0 $,終點為 $ y $ 的便便傳送門,可以在 $ 0 $ 的貢獻下將牛糞從 $ 0 $ 傳送到 $ y $,同樣貢獻為不用傳送門走的距離,最小化貢獻和,求最小值。

$ 1 \le n \le 10^5, -10^8 \le a_i, b_i \le 10^8 $。

Examples

Input_1

3
-5 -7
-3 10
-2 7

Output_1

10

Solution

這道題告訴我們,題做不出來的時候要多去去廁所,去溜達一圈之後或許就突然想明白了。。

我感覺還算是一道挺有意思的題,比較奇妙,難度適中,藍色評的也很合理。

顯然當 $ y $ 確定後對於每一對 $ a_i, b_i $ 的貢獻即為 $ f(y)i = \min(\vert a_i - b_i \vert, \vert a_i \vert + \vert y - b_i \vert) $,我們的答案即為 $ \sum{i = 1}^n f(y)_i $。

此時顯然如果有 $ \vert a_i - b_i \vert \lt \vert a_i \vert $,解一下就是 $ a_i \ge b_i \gt 0 \vee 0 \le a_i \lt b_i \lt 2a_i \vee 0 \gt a_i \gt b_i \gt 2a_i \vee a_i \lt b_i \lt 0 $,那麼一定不走傳送門,也就是選前者,這樣的話對於這個 $ f(y)_i $ 就是一條直線,不過這一大坨不等式看著就很陰間,畫個圖吧:

觀察發現剩下的可能性就只有 $ 0 \le 2a_i \lt b_i \vee b_i \lt2a_i \le 0 \vee a_i \lt 0 \lt b_i \vee b_i \lt 0 \lt a_i $ 了,而這一段區間則與 $ y $ 相關,需要額外討論一下。

此時的原式為 $ f(y)_i = \min(\vert a_i - b_i \vert, \vert a_i \vert + \vert y - b_i \vert) $,考慮分類討論,如在 $ 0 \le 2a_i \lt b_i $ 的條件下,原式轉化為 $ \min(b_i - a_i, a_i + \vert y - b_i \vert) $,然後把 $ y $ 和 $ b_i $ 之間的關係討論一下(這裡就很簡單了,不多贅述,注意一下 $ b_i \lt 2b_i - 2a_i $ 在條件下恆成立即可),最終可以寫成一下柿子:

$ 0 \le 2a_i \lt b_i $:

\[f(y)_i = \left\{ \begin{array}{ll} b_i - a_i &\quad y \in (-\infty, 2a_i] \cup [2b_i - 2a_i, +\infty) \\ -y + a_i + b_i &\quad y \in (2a_i, b_i) \\ y + a_i - b_i &\quad y \in [b_i, 2b_i - 2a_i) \end{array} \right. \]

然後在 $ b_i \lt2a_i \le 0 $ 同理可以推出:

$ b_i \lt2a_i \le 0 $:

\[f(y)_i = \left\{ \begin{array}{ll} a_i - b_i &\quad y \in (-\infty, 2b_i - 2a_i] \cup [2a_i, +\infty) \\ -y - a_i + b_i &\quad y \in (2b_i - 2a_i, b_i) \\ y - a_i - b_i &\quad y \in [b_i, 2a_i) \end{array} \right. \]

剩下的兩個區間也同理推導一下即可:

$ a_i \lt 0 \lt b_i $:

\[f(y)_i = \left\{ \begin{array}{ll} b_i - a_i &\quad y \in (-\infty, 0] \cup [2b_i, +\infty) \\ -y - a_i + b_i &\quad y \in (0, b_i) \\ y - a_i - b_i &\quad y \in [b_i, 2b_i) \end{array} \right. \]

$ b_i \lt 0 \lt a_i $:

\[f(y)_i = \left\{ \begin{array}{ll} a_i - b_i &\quad y \in (-\infty, 2b_i] \cup [0, +\infty) \\ -y + a_i + b_i &\quad y \in (2b_i, b_i) \\ y + a_i - b_i &\quad y \in [b_i, 0) \end{array} \right. \]

現在我們也就能確定下來每一條 $ f(y)_i $ 的形狀了,都是類似下圖的形狀,只是 “轉折點” 不同,和 $ y $ 無關的認為其沒有轉折點即可。

此時我們就需要考慮一下求 $ \sum_{i = 1}^nf(y)_i $ 了。

不難想到 $ O(n) $ 記錄一下每一條線的 “轉折點” 的位置,建立一個差分陣列,然後每條線段斜率變為 $ -1 $ 之後對應位置加上 $ -1 $,斜率變為 $ 1 $ 之後加上 $ 2 $,變回與 $ y $ 相關之後再加上 $ -1 $,然後我們把差分陣列做個字首和,這樣當前的字首和陣列的值就是 $ i $ 相對 $ i - 1 $ 的總答案變化量,對於 $ 0 $ 處我們認為其為 $ \sum_{i = 1}^n \vert a_i - b_i \vert $,然後在字首和上再做一個字首和,令其為 $ sum_i $,則不難想到答案即為 $ \min{sum_i} $,然後這裡因為座標值域範圍很大,所以考慮離散化,為了寫著方便,直接開一個 map 存即可,排序也省了。

至此,我們就做完了這道奇怪的大分類討論,複雜度 $ O(n \log n) $,卡在排序上。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template< typename T = int >
inline T read(void);

int N;
ll origin(0);
ll mn(LONG_LONG_MAX);
map < ll, ll > mp;
ll sum[310000]; int cnt(0);

void Insert(int p, int v){
    if(mp.find(p) == mp.end())mp.insert({p, v});
    else mp[p] += v;
}
void InsertAll(int sp1, int sp2, int sp3){
    Insert(sp1, -1);
    Insert(sp2, 2);
    Insert(sp3, -1);
}

int main(){
    N = read();
    for(int i = 1; i <= N; ++i){
        int a = read(), b = read();
        origin += abs(a - b);
        if(0 <= 2 * a && 2 * a < b)InsertAll(2 * a, b, 2 * b - 2 * a);
        else if(b < 2 * a && 2 * a <= 0)InsertAll(2 * b - 2 * a, b, 2 * a);
        else if(a < 0 && 0 < b)InsertAll(0, b, 2 * b);
        else if(b < 0 && 0 < a)InsertAll(2 * b, b, 0);
    }
    ll cur(0), sum(origin); int lft(INT_MIN);
    mn = origin;
    for(auto v : mp){
        sum += (ll)cur * (v.first - lft);
        cur += v.second, lft = v.first;
        mn = min(mn, sum);
    }
    printf("%lld\n", mn);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

LG-P4088 [USACO18FEB]Slingshot P

題面

數軸上存在 $ n $ 個便便彈弓,每個有 $ x_i, y_i, t_i $ 表示該便便彈弓可以用 $ t_i $ 的時間將便便從 $ x_i $ 發射到 $ y_i \(。也可以直接開糞車送便便,\) d $ 距離需要花費 $ d $ 時間。有 $ m $ 個詢問,每個有 $ a_i, b_i $,表示求讓一坨便便從 $ a_i $ 送到 $ b_i $,最多可以使用一次便便彈弓,最少需要花費多少時間。

$ 1 \le n, m \le 10^5, 0 \le x_i, y_i, t_i, a_i, b_i \le 10^9 $。

Examples

Input_1

2 3
0 10 1
13 8 2
1 12
5 2
20 7

Output_1

4
3
10

Solution

和上一題核心思想差不多,依然考慮,對於詢問 $ a, b $,不使用彈弓就是 $ \lvert a - b \rvert $,使用彈弓 $ x, y, t $ 的話結果就是 $ \lvert a - x \rvert + \lvert b - y \rvert + t $,我們需要最小化這個值。

看一下這個柿子實際上就是兩個點之間的曼哈頓距離再加上一個值,說人話就是兩點之間的橫縱座標差的絕對值之和再加上點 $ (x, y) $ 的點權,然後發現這玩意變成二維數點了。。首先討論一下絕對值,把絕對值拆掉,離散化,然後按 $ x $ 排序,把合法的塞到權值樹狀數組裡,值就是對應點 $ (x, y) $ 的那些資訊,隨便搞一下就行了,細節不少。。

然後在具體實現的時候可以不用分類討論寫四個樹狀陣列,直接清空原來的然後將座標軸旋轉一下,可以認為是讓對應的大小關係反轉,也就是把 $ x $ 和 $ rx $ 取個相反數即可。這裡 $ x $ 是離散化之後的值,只保留大小關係,而樹狀陣列上索引需要為正,所以每次 “旋轉座標軸” 的時候需要 $ x \leftarrow -x + lim + 1, rx \leftarrow -rx $,後者不需要轉正是因為我們實際上就是把原來的 $ a - x $ 變成 $ x - a $,此時前者為負,後者一定為正。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

#define NM (N + M)

template< typename T = int >
inline T read(void);

vector < int > data;
struct Node{
    int idx;
    int x, y;
    int rx, ry;
    int t;
    friend const bool operator < (Node a, Node b){return a.x < b.x;}
}nod[210000];

int N, M;
ll lim;
ll ans[110000];

class BIT{
private:
    ll tr[410000];
public:
    void clear(void){memset(tr, 0x3f, sizeof tr);}
    int lowbit(int x){return x & -x;}
    void Modify(int x, ll v){while(x <= lim)tr[x] = min(tr[x], v), x += lowbit(x);}
    ll Query(int x){ll ret((ll)INT_MAX * 114514); while(x)ret = min(ret, tr[x]), x -= lowbit(x); return ret;}
}bit;

void Make(void){
    sort(nod + 1, nod + NM + 1);
    bit.clear();
    for(int i = 1; i <= NM; ++i){
        if(!~nod[i].t)ans[nod[i].idx] = min(ans[nod[i].idx], bit.Query(nod[i].y) + nod[i].rx + nod[i].ry);
        else bit.Modify(nod[i].y, (ll)-nod[i].rx - nod[i].ry + nod[i].t);
    }
}

int main(){
    memset(ans, 0x3f, sizeof ans);
    N = read(), M = read();
    for(int i = 1; i <= N; ++i){
        int x = read(), y = read(), t = read();
        nod[i] = Node{i, x, y, x, y, t};
        data.emplace_back(x), data.emplace_back(y);
    }
    for(int i = 1; i <= M; ++i){
        int x = read(), y = read();
        nod[i + N] = Node{i, x, y, x, y, -1};
        data.emplace_back(x), data.emplace_back(y);
        ans[i] = abs(y - x);
    }sort(data.begin(), data.end());
    data.erase(unique(data.begin(), data.end()), data.end());
    lim = data.size();
    for(int i = 1; i <= NM; ++i)
        nod[i].x = distance(data.begin(), lower_bound(data.begin(), data.end(), nod[i].x) + 1),
        nod[i].y = distance(data.begin(), lower_bound(data.begin(), data.end(), nod[i].y) + 1);
    Make();
    for(int i = 1; i <= NM; ++i)
        nod[i].x = -nod[i].x + lim + 1, nod[i].rx = -nod[i].rx;
    Make();
    for(int i = 1; i <= NM; ++i)
        nod[i].y = -nod[i].y + lim + 1, nod[i].ry = -nod[i].ry;
    Make();
    for(int i = 1; i <= NM; ++i)
        nod[i].x = -nod[i].x + lim + 1, nod[i].rx = -nod[i].rx;
    Make();
    for(int i = 1; i <= M; ++i)printf("%lld\n", ans[i]);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

LG-P4265 [USACO18FEB]Snow Boots S

題面

給定序列 $ f_n $ 表示位置 $ i $ 的積雪深度,保證 $ f_1 = f_n = 0 $,共有 $ b $ 雙靴子,每雙有 $ s_i, d_i $,表示最大可承受 $ s_i $ 深度的積雪,可以走 $ d_i $ 的距離。zpair 可以在任意時刻丟掉序列最前面的一雙靴子或者丟掉腳上的換上序列最前面的一雙靴子,換靴子時必須保證其身上的和換上的可承受深度都要大於當前位置積雪深度,且穿著某雙靴子走的路程必須不大於 $ d_i $,最小化走到 $ n $ 需要丟掉的靴子數,求最小值。

Tips:zpair 每次走 $ d_i $ 距離時中間的積雪深度可以大於 $ s_i $,保證起始和終點滿足條件即可(這也是我理解錯的地方)。

$ 2 \le n, b, \le 250, 0 \le f_i, s_i \le 10^9, 1 \le d_i \le n $。

Examples

Input_1

10 4
0 2 8 3 6 7 5 1 4 0
2 3
4 2
3 4
7 1

Output_1

2

Solution

題目讀完沒啥好思路,然後一看資料範圍 $ 250 $,直接就口糊了一個 $ \texttt{2D2D} $ 的 dp,然後感覺 $ 250^4 $ 過不了,所以 “討論” 了一下優化成了狀態 $ O(nb) $ 轉移 $ O(b \log n) $ 最終 $ O(b^2 n \log n) $ 的肯定能過的做法,然後發現把這玩意變成預處理直接就是 $ O(n^2b + nb^2) $ 了,顯然能過。大致思路是令 $ pre(i, j) $ 表示第 $ i $ 雙靴子在 $ j $ 的位置上最多可以走 $ j $ 和 $ j $ 以前最長多遠,或者也可以認為是求字首裡最後一個大於當前數的位置 $ +1 $,這東西 $ O(n^2b) $ 就完事了,然後考慮令 $ dp(i, j) $ 表示用前 $ i $ 雙靴子並欽定用 $ i $,走到 $ j $ 位置是否可以到達(最開始設的是至少需要丟棄多少,但是實際上 $ i - 1 $ 就是答案,記錄能否到達即可),這玩意大概就是列舉上一個用的靴子,然後用 $ pre $ 轉移一下即可,複雜度是 $ O(nb^2) $ 的,當然我的方程寫的有點小問題(正確性好像也有點問題),不過也沒必要調,這個東西很不優而且邊界不好設定。

考慮正解,$ \texttt{2D2D} $ 的 dp 能過。。狀態不變,考慮轉移的時候列舉換的下一雙鞋和走到的位置,然後加點剪枝就過了。對於複雜度正確的方法可以把狀態變成 $ dp(i) $ 表示前 $ i $ 能走多遠之類的,變成 $ \texttt{1D2D} $ 的就行了。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template< typename T = int >
inline T read(void);

int N, B;
int dep[300];
int s[300], d[300];
bool dp[300][300];
// int dp[300][300];
// int pre[300][300];

int main(){
    // memset(dp, 0x3f, sizeof dp);
    // for(int i = 0; i <= 260; ++i)dp[i][0] = i;
    dp[1][1] = 1;
    N = read(), B = read();
    for(int i = 1; i <= N; ++i)dep[i] = read();
    for(int i = 1; i <= B; ++i)s[i] = read(), d[i] = read();

    // Waiting for debugging...
    // for(int i = 1; i <= B; ++i)
    //     for(int j = 1; j <= N; ++j)
    //         for(int k = j; k >= 1; --k)
    //             if(dep[k] <= s[i] && j - k + 1 <= d[i])pre[i][j] = k;
    //             else break;
    // for(int i = 1; i <= B; ++i)
    //     for(int j = 1; j <= N; ++j)
    //         if(dep[j] <= s[i])
    //             for(int k = i - 1; k >= 0; --k)
    //                 if(pre[i][j])dp[i][j] = min(dp[i][j], dp[k][pre[i][j] - 1] + i - k - 1);
    // int mn(INT_MAX);
    // for(int i = 1; i <= B; ++i)mn = min(mn, dp[i][N]);
    // printf("%d\n", mn);

    for(int i = 1; i <= B; ++i)
        for(int j = 1; j <= N; ++j)
            if(dp[i][j])
                for(int k = i; k <= B; ++k)
                    if(s[k] >= dep[j])
                        for(int l = j + 1; l <= min(N, j + d[k]); ++l)
                            if(s[k] >= dep[l])
                                dp[k][l] = true;
    for(int i = 1; i <= B; ++i)if(dp[i][N])printf("%d\n", i - 1), exit(0);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

LG-P4269 [USACO18FEB]Snow Boots G

題面

給定長度為 $ n $ 的序列 $ f_n \(,\) b $ 組詢問每次 $ s_i, d_i $,求 $ f_n $ 中是否存在一段連續的長度超過 $ d_i $ 且每個數均大於 $ s_i $ 的子串,不存在輸出 $ 1 $,存在輸出 $ 0 $。

$ 1 \le n, b \le 10^5, 0 \le f_i, s_i \le 10^9, 1 \le d_i \le n - 1 $。

Examples

Input_1

8 7
0 3 8 5 6 9 0 0
0 5
0 6
6 2
8 1
10 1
5 3
150 7

Output_1

0
1
1
0
1
1
1

Solution

題面簡化之後一個很顯然的做法就是線段樹,認為葉子節點符合要求的時候就是 $ 1 $,不符合要求為 $ 0 $,每次等於是一些單點修改,然後整個區間查詢最長的連續 $ 1 $ 的串(這東西很簡單吧,維護最長串,左側最長串,右側最長串即可)當然嗯搞肯定不行,所以考慮把序列和詢問都離線下來降序排個序,這樣的話對於上一個詢問不符合的 $ f_i $ 一定這次也不符合,也就變成了一個類似雙指標的東西,這樣我們就可以讓修改次數變成 $ O(n) $ 的,然後這樣線段樹做法的話就是 $ O(n \log n + q \log q) $。然後線段樹碼量比較大,所以考慮直接用雙向連結串列,維護一下當前有多長的不符合條件的子串就行了,不難實現,注意為了更方便求連結串列之間在原來位置的距離,用陣列模擬連結串列會更方便,複雜度卡在排序上,但是求解變成 $ O(n + q) $ 了。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template< typename T = int >
inline T read(void);

// struct List{
//     List *pre, *nxt;
//     int dep;
// };
// List* lst[110000];
struct List{
    int pre, nxt;
    int dep;
}lst[110000];
int N, B;
struct Snow{
    int idx, dep;
    friend const bool operator < (const Snow &a, const Snow &b){return a.dep > b.dep;}
}snow[110000];
struct Boot{
    int idx, dis, dep;
    friend const bool operator < (const Boot &a, const Boot &b){return a.dep > b.dep;}
}boot[110000];
bool ans[110000];

int main(){
    N = read(), B = read();
    for(int i = 1; i <= N; ++i){
        // lst[i]->dep = read();
        // if(i != 1)lst[i]->pre = lst[i - 1];
        // if(i != N)lst[i]->nxt = lst[i + 1];
        snow[i] = Snow{i, read()};
        lst[i] = List{i - 1, i + 1, snow[i].dep};
    }
    for(int i = 1; i <= B; ++i){int s = read(), d = read(); boot[i] = Boot{i, d, s};}
    sort(snow + 1, snow + N + 1), sort(boot + 1, boot + B + 1);
    int cur(0), mx(0);
    for(int i = 1; i <= B; ++i){
        while(cur <= N - 1 && snow[cur + 1].dep > boot[i].dep){
            ++cur;
            lst[lst[snow[cur].idx].nxt].pre = lst[snow[cur].idx].pre;
            lst[lst[snow[cur].idx].pre].nxt = lst[snow[cur].idx].nxt;
            mx = max(mx, lst[snow[cur].idx].nxt - lst[snow[cur].idx].pre);
        }if(mx <= boot[i].dis)ans[boot[i].idx] = true;
    }
    for(int i = 1; i <= B; ++i)printf("%d\n", ans[i] ? 1 : 0);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

LG-P4268 [USACO18FEB]Directory Traversal G

題面

sssmzy 在他的電腦中儲存了很多學習資料,我們都知道在系統大多數路徑中都存在名為 .. 的路徑,通過此路徑可以回到上一級(通過 ... 等連線的一般叫做相對路徑)。給定一些資料夾和檔案之間的關係,sssmzy 可以處於某個資料夾中,他要訪問所有的檔案,顯然這些檔案相對於其所在資料夾會有很多路徑,你需要最小化每個檔案路徑長度和,並輸出。特別地,我們不考慮使用 ./

$ 2 \le n \le 10^5 $。

對於樣例,其檔案之間的結構為:

bessie/
--folder1/
----file1
----folder2/
------file2
--folder3/
----file3
--file4

可以證明從 folder2 出發會有最小路徑長度和,路徑為:

../file1
file2
../../folder3/file3
../../file4

關於輸入格式:
第一行包含一個整數N(\(2 \leq N \leq 100,000\)),為所有檔案和資料夾的總數量。為了便於輸入,每個物件(檔案或資料夾)被賦予一個唯一的 $ 1 $ 至 $ N $ 之間的 ID,其中 ID 1 指的是頂層資料夾。
接下來有 $ N $ 行。每行的第一項是一個檔案或是資料夾的名稱。名稱僅包含小寫字母 $ a-z $ 和數字 $ 0-9 $,長度至多為 $ 16 $ 個字元。名稱之後是一個整數 $ m $。如果 $ m $ 為 $ 0 $,則該物件是一個檔案。如果 $ m > 0 $,則該物件是一個資料夾,並且該資料夾下共有 $ m $ 個檔案或資料夾。在 $ m $ 之後有 $ m $ 個整數,為該資料夾下的物件的 ID。

Examples

Input_1

8
bessie 3 2 6 8
folder1 2 3 4
file1 0
folder2 1 5
file2 0
folder3 1 7
file3 0
file4 0

Output_1

42

Solution

一個有點像換根 DP 但是沒換根的樹形 DP。

首先根據定義,顯然不會有空資料夾,所以葉子節點均為資料夾。

首先以根目錄的資料夾為根 dfs 一遍,記錄一大堆東西,以根目錄為根的路徑長度和 $ f(x) $,其自身檔名長度 $ \omega(x) \((不包括 `/`),特別地,\) \omega(root) = 0 $,以 $ root $ 為根 $ x $ 所在子樹葉子節點數量 $ leaf(x) $。

然後再做一遍不換根的換根 DP,同樣深搜,令子節點答案為 $ f(y) $,父節點為 $ f(x) $,顯然有 $ f(y) = f(x) - leaf(y) \times (\omega(y) + 1) + (leaf(root) - leaf(y)) \times 3 $。

至於 $ \times 3 $ 就是 ../,不難理解吧,這樣跑一遍求一下最大的 $ f(x) $ 就行。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template< typename T = int >
inline T read(void);

struct Edge{
    Edge* nxt;
    int to;
    OPNEW;
}ed[210000];
ROPNEW(ed);
Edge* head[110000];

int N;
ll f[110000];
int leaf[110000], w[110000];
ll dis[110000];
ll mn;

void dfs_pre(int p = 1, int fa = 0){
    if(p != 1 && !head[p]->nxt)leaf[p] = 1, f[1] += dis[fa] + w[p];
    else dis[p] = p == 1 ? 0 : dis[fa] + w[p] + 1;
    for(auto i = head[p]; i; i = i->nxt)if(SON != fa)dfs_pre(SON, p), leaf[p] += leaf[SON];
}
void dfs(int p = 1, int fa = 0){
    if(p != 1 && head[p]->nxt)f[p] = f[fa] - (ll)leaf[p] * (w[p] + 1) + (ll)(leaf[1] - leaf[p]) * 3, mn = min(mn, f[p]);
    for(auto i = head[p]; i; i = i->nxt)if(SON != fa)dfs(SON, p);
}

int main(){
    N = read();
    for(int i = 1; i <= N; ++i){
        string dir;
        cin >> dir;
        w[i] = i == 1 ? 0 : (int)dir.size();
        int M = read();
        for(int j = 1; j <= M; ++j){
            int son = read();
            head[i] = new Edge{head[i], son};
            head[son] = new Edge{head[son], i};
        }
    }
    dfs_pre();
    mn = f[1];
    dfs();
    printf("%lld\n", mn);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

LG-P4267 [USACO18FEB]Taming the Herd G

題面

原題面說的很奇怪,我理解了半天才看懂,所以這題就不簡化題面了。。

一大清早,Farmer John就被木材破裂的聲音吵醒了。是這些奶牛們乾的,她們又逃出牛棚了!
Farmer John已經厭煩了奶牛在清晨出逃,他覺得受夠了:是時候採取強硬措施了。他在牛棚的牆上釘了一個計數器,追蹤從上次出逃開始經過的天數。所以如果某一天早上發生了出逃事件,這一天的計數器就為\(0\);如果最近的出逃是\(3\)天前,計數器讀數就為\(3\)。Farmer John一絲不苟地記錄了每一天計數器的讀數。

年末到了,Farmer John準備做一些統計。他說,你們這些奶牛會付出代價的!然而他的某些記錄看上去不太對勁……

Farmer John想要知道從他開始記錄以來發生過多少次出逃。但是,他懷疑這些奶牛篡改了它的記錄,現在他所確定的只有他是從發生出逃的某一天開始記錄的。請幫助他求出,對於每個從他開始記錄以來可能發生的出逃次數,他被篡改了的記錄條數的最小值。

輸入格式(檔名:taming.in):
輸入的第一行包含一個整數\(N\)\(1 \leq N \leq 100\)),表示從Farmer John開始對奶牛出逃計數器進行計數以來已經經過的天數。
第二行包含\(N\)個空格分隔的整數。第\(i\)個整數是一個非負整數\(a_i\)(不超過\(100\)),表示在第\(i\)天計數器的數字是\(a_i\),除非奶牛篡改了這一天的記錄條目。

輸出格式(檔名:taming.out):
輸出包含\(N\)個整數,每行一個。第\(i\)個整數為所有發生\(i\)次出逃的事件序列中,與該事件序列不一致的記錄條目條數的最小值。

陽間題面:

題目說在一個牛棚裡有一個計數器,用來記錄每一天有沒有奶牛逃跑。
假設今天是第 i 天,如果今天有奶牛逃跑,那麼計數器就為 0 。
如果在第 ij 天有奶牛逃跑,那麼計數器就為 j
但是記錄有可能被篡改,給定一個記錄的數列(有可能被篡改過),求在有 i 個奶牛逃跑時的最小被篡改量。

Input_1

6
1 1 2 0 0 1

Output_1

4
2
1
2
3
4

Solution

一道比較裸的 DP,難度在於理解題意。

令 $ dp(i, j) $ 表示前 $ i $ 個數裡共跑了 $ j $ 頭奶牛,欽定 $ i $ 一定跑了一頭牛,然後 $ \texttt{2D2D} $ 的 dp 就出來了,$ dp(k, j) = \min{dp(i, j - 1) + cal(i + 1, k)} \(,\) i \lt k \le n $。可以預處理優化到 $ \texttt{2D1D} $,但是沒必要。。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template< typename T = int >
inline T read(void);

int N;
int a[110];
int dp[110][110];
int cal(int s, int t){
    int cnt(0);
    for(int i = s; i <= t; ++i)if(a[i] != i - s)++cnt;
    return cnt;
}

int main(){
    memset(dp, 0x3f, sizeof dp);
    dp[0][0] = 0;
    N = read();
    for(int i = 1; i <= N; ++i)a[i] = read();
    for(int i = 0; i <= N; ++i)
        for(int j = 1; j <= N; ++j)
            for(int k = i + 1; k <= N; ++k)
                dp[k][j] = min(dp[k][j], dp[i][j - 1] + cal(i + 1, k));
    for(int i = 1; i <= N; ++i)printf("%d\n", dp[N][i]);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

LG-P4270 [USACO18FEB]Cow Gymnasts P

題面

存在 $ n $ 個平臺環形排列,每個平臺可以放置 $ [1, n] $ 頭奶牛,每次操作時,對於第 $ i $ 層的奶牛,會順時針移動 $ i - 1 $ 個平臺並落下,求有多少種排列能使無論多少次操作每個平臺的奶牛數都不改變。

$ 1 \le n \le 10^{12} $。

對於樣例,有 $ (1, 1, 1, 1), (2, 2, 2, 2), (3, 3, 3, 3), (4, 4, 4, 4), (2, 3, 2, 3), (3, 2, 3, 2) $。

Examples

Input_1

4

Output_1

6

Solution

一道純粹的人類智慧題。。。

然後我們這裡定義的迴圈週期並不是一般圓周運動繞一圈的操作次數,而是一頭原來在第 $ i $ 層且最高為 $ \xi $ 層的牛再次到第 $ i $ 層且最高為 $ \xi $ 層所需要的旋轉次數。也就是對於一個合法的排列,兩個同一高度平臺之間的距離即為平臺內所有牛的迴圈週期。

首先對於符合條件的排列,有好幾個奇怪的性質:

  1. 對於第 $ i $ 層的奶牛,只能是從其他平臺第 $ i $ 層的奶牛平移過來,而不可以是從更高層的奶牛掉下來。

證明:因為是符合條件的排列,我們假設序列中最高的層數為 $ m $,那麼一定是前面的 $ m - 1 $ 個平臺各自給這個平臺貢獻一頭奶牛,因為如果有往前數第 $ m $ 個的貢獻,那麼那個平臺至少要有 $ m + 1 $ 頭奶牛,矛盾。如果在前 $ m - 1 $ 裡有至少任意一個沒有貢獻,那麼當前這個臺子奶牛就會少至少一個,也矛盾,所以簡單想一下剛才的過程,前面第一個貢獻當前的第 $ 2 $ 層,第二個貢獻第 $ 3 $ 層,$ \cdots $,第 $ m - 1 $ 個貢獻當前的第 $ m $ 層,而第 $ m - 1 $ 個能移動 $ m - 1 $ 那麼其長度也就必須至少為 $ m $,然後以此類推即可證明所有層數都是由對應層數平移過來的,得證。

  1. 對於第 $ i $ 層奶牛的迴圈週期(定義參考伊始)是 $ i $ 的約數。

證明:顯然某一時刻第 $ i $ 層的某頭奶牛一定是這層的週期為 $ T_i $ 的奶牛移動 $ k $ 次到達的,即 $ i = kT_i $,得證。

  1. 第 $ i - 1 $ 層奶牛迴圈週期是第 $ i $ 層奶牛迴圈週期的約數。

證明:考慮由性質一,第 $ i $ 層的奶牛一定還會到第 $ i $ 層,而到達的位置的第 $ i $ 層已經跑了,所以一定是有 $ i - 1 $ 層的奶牛一直墊著它走的,否則便會掉到小於 $ i $ 的位置了,所以下層的週期一定是上層的約數,即 $ T_{i - 1} \mid T_i $,得證。

  1. 任意兩個平臺之間的奶牛數量差不超過 $ 1 $。

證明:由性質二不難得出 $ T_i \mid i, T_{i + 1} \mid i + 1 $,由性質三不難得出 $ T_{i} \mid T_{i + 1} $,又 $ \gcd(i, i + 1) = 1 $,那麼顯然 $ \gcd(T_i, T_{i + 1}) = 1 $,兩數互質,前者又是後者的約數,所以顯然前者為 $ 1 $,所以 $ T_1 = T_2 = \cdots = T_{n - 1} = 1 $。所以對於某個層數最高為 $ i $ 的,每次位移的距離是 $ i - 1 $,週期又為 $ 1 $,那麼每隔 $ i - 1 $ 個就是相同的層數,這東西不難想到就是任意兩者之間差不超過 $ 1 $.

以此我們便可以得出結論:

\[ans = 2 - n + \sum_{i = 1}^{n - 1}2^{\gcd(n, i)} \]

證明:首先列舉層數最小的平臺有 $ i $ 層,不難想到對於最小平臺有 $ i $ 層時,迴圈週期一定是 $ i $ 的約數,且一共有 $ n $ 個平臺,那麼迴圈週期也一定為 $ n $ 的約數,以此不難想到,此時最大的迴圈週期為 $ \gcd(n, i) $,此時我們舉個 $ n = 6, i = 3, \gcd = 3 $ 的例子:

此時根據我們前面的性質一定有標號相同的點值相同,那麼此時 $ 2^{\gcd(n, i)} $ 就代表著列舉 $ A, B, C $ 是否為 $ i $,但是此時如果三個值均非 $ i $ 的話,最小值便不能保證為 $ i $,此時還需要對此次的貢獻 $ -1 $。

然後此時我們還要考慮,為什麼僅列舉是否為 $ i $ 就可以不重不漏了,考慮如欽定 $ A = i $ 時,且欽定 $ B $ 不為 $ i $,則 $ B $ 一定為 $ i + 1 $ 或 $ i - 1 $,後者則最小值會變化,不合法,所以如果不是 $ i $ 那麼一定是 $ i + 1 $。所以此時如果還欽定 $ C $ 不是 $ i $,那麼它要麼是 $ i + 1 $ 要麼是 $ i + 2 $,而 $ C $ 與下一個 $ A $ 相連,$ i + 2 $ 和 $ i $ 的差大於 $ 1 $ 了,也不合法。當然我們考慮 $ i + 2 = 5 $,由性質二,發現 $ 3 \nmid 5 $,也不合法,所以仍然為 $ i + 1 $。那麼對於這個例子,顯然一個數要麼是 $ i $ 要麼不是,不是的時候數也唯一確定,故可以如此列舉。

隨便舉幾個例子可以發現這個結論似乎正確,那麼我們現在嘗試嚴謹一點地去證明,有結論,對於所有非 $ i $ 的點的值一定均為 $ i + 1 $。

首先考慮如果有非 $ i $ 的點,那麼一定至少要有一個 $ i + 1 $,這個從我們之前的證明即可得出,因為差最大為 $ 1 $,又不可以是 $ i - 1 $。此時如果後面的值是 $ i + 2 $,那麼顯然此時 $ T_{i + 1} \ge 2 $,並且此時因為存在 $ i + 2 $,那麼最大值一定不是 $ i + 1 $,所以從性質四的證明過程可以得到 $ T_{i + 1} = 1 $,顯然矛盾。而如果所有非 $ i $ 均為 $ i + 1 $,那麼 $ i + 1 $ 即為最大值,觀察性質發現有且僅有最大值是可以不符合恆等於 $ 1 $ 的條件的,所以這樣才是合法的。故得證。

所以換一個說法理解,我們列舉的便為此處是 $ i $ 還是 $ i + 1 $,且不能均為 $ i + 1 $,此時貢獻為 $ 2^{\gcd(n, i)} - 1 $,考慮如果 $ i = n $,那麼不存在 $ i + 1 $ 了,此時需要特判,不難想到最小為 $ n $ 最大為 $ n $ 那麼全是 $ n $ 則為唯一的方案,如此最終答案便為:

\[\begin{aligned} ans &=\sum_{i = 1}^{n - 1}(2^{\gcd(n, i)} - 1) + 1 \\ &=2 - n + \sum_{i = 1}^{n - 1}2^{\gcd(n, i)} \\ &=2 - n - 2^n + \sum_{i = 1}^{n}2^{\gcd(n, i)} \end{aligned} \]

然後發現數據範圍這個柿子肯定過不去,於是考慮優化,繼續推柿子:

\[\begin{aligned} \sum_{i = 1}^{n}2^{\gcd(n, i)} &= \sum_{j = 1}^n 2^j \sum_{i = 1}^{n}[\gcd(n, i) = j] \\ &= \sum_{j = 1}^n 2^j \sum_{i = 1}^{n}[j \mid i \land j \mid n \land \gcd(\dfrac{n}{j}, \dfrac{i}{j}) = 1] \\ &= \sum_{j = 1}^n (2^j \times \varphi(\dfrac{n}{j}) \times [j \mid n]) \\ &= \sum_{j \mid n} (2^j \times \varphi(\dfrac{n}{j})) \\ &= \sum_{j \mid n} (2^{\frac{n}{j}} \times \varphi(j)) \end{aligned} \]

這個式子應該是可以繼續推下去直到嚴格 $ O(\sqrt{n}\log n) $ 的,但是沒必要,到目前這個形式就已經可以通過精細實現打倒這個複雜度了。我們發現如果無腦列舉,找因數是 $ O(\sqrt{n}) $ 的,每個因數求尤拉函式也是 $ O(\sqrt{n}) $ 的,最後會退化成 $ O(n) $,線性篩之類的更不行了,如果可以的話或許 Min25篩 之類的科技可以 $ O(n^{\frac{2}{3}}) $ 實現,剛好能過,不過 duck 不必。

顯然我們可以通過分解質因數求尤拉函式,具體地,令 $ p_i $ 為質數且 $ c_i \neq 0 $,如果有:

\[n = \prod_{i = 1}^k p_i^{c^i} \]

那麼:

\[\varphi(n) = n \times \prod_{i = 1}^k \dfrac{p_i - 1}{p_i} \]

然後我們答案式子列舉的是 $ n $ 的因子,顯然可以通過列舉其所有質因子不重不漏地湊出來所有的因子,於是寫個樸素搜尋,暴力列舉每個因子有多少個,以及當前的乘積,和存在的質因子的乘積等等,如此便可以 $ O(1) $ 求出每個需要的尤拉函式,複雜度為因數個數,即 $ O(\sqrt{n}) $,然後剩下的 $ \log $ 複雜度是因為求 $ 2^j $ 的時候快速冪的複雜度,理論上用左移會更優,但是可能爆 long long。然後過程中是需要先讓 $ n \div \prod p_i $ 然後再乘 $ \prod p_i - 1 $,否則會爆 long long,當然像我一樣直接用 __int128_t 可以直接忽略這些問題。

至此此題解決,還是很精妙的。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

#define MOD (ll)(1e9 + 7)

template< typename T = int >
inline T read(void);

ll N;
int tot(0);
pair < ll, int > fact[1100000];
int cur[1100000];
__int128_t ans(0);

__int128_t qpow(ll a, ll b){
    __int128_t ret(1), mul(a);
    while(b){
        if(b & 1)ret = ret * mul % MOD;
        b >>= 1;
        mul = mul * mul % MOD;
    }return ret;
}

void dfs(int p = 1, ll base = 1, __int128_t phi = 1, __int128_t div = 1){
    if(p > tot){
        phi *= base, phi /= div, phi %= MOD;
        ans = (ans + phi * qpow(2, N / base) % MOD) % MOD;
        return;
    }
    dfs(p + 1, base, phi, div);
    phi *= fact[p].first - 1;
    div *= fact[p].first;
    for(int i = 1; i <= fact[p].second; ++i)
        base *= fact[p].first, dfs(p + 1, base, phi, div);
}

int main(){
    N = read < ll >();
    ll tmp(N); ll cur(2), cnt(0);
    while(tmp > 1){
        if(cur * cur > tmp)break;
        while(tmp % cur == 0)tmp /= cur, ++cnt;
        if(cnt)fact[++tot] = {cur, cnt}, cnt = 0;
        ++cur;
    }if(tmp > 1)fact[++tot] = {tmp, 1};
    dfs();
    ans = ((((ans + 2 - N) % MOD) - qpow(2, N)) % MOD + MOD) % MOD;
    printf("%lld\n", (ll)ans);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

LG-P4271 [USACO18FEB]New Barns P

題面

奇怪題,先咕著,laterrrrrr 再來寫。

Examples

Input_1


Output_1


Solution

Code


UPD

update-2022_11_10 初稿