1. 程式人生 > 實用技巧 >2020牛客多校第二場部分題解

2020牛客多校第二場部分題解

A B C D E F G H I J K
1 2 2 2 1 1

// 0 - unsolved 1- solved 2- solved-in-contest

其他題被隊友補了,就沒彙總題解。

Boundary

思路:

列舉這\(\mathit n\)個點的任意兩個,然後與原點\((0,0)\)三點若不共線的話,可以確定一個唯一的圓。

我們可以將圓心座標求出,然後將圓心座標擴大\(1e6\)倍之後捨去小數位轉成long long資料型別。

然後找出出現次數最大的圓心個數\(num\)。(這裡用map的話會TLE,改成vector排序查重複元素更快。)

根據組合數學知識,我們要求得的答案\(ans\)

滿足\(ans^2-ans=num\)

程式碼:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x)  if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '\n' : ' ');}}
void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '\n' : ' ');}}
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
struct Point
{
    double x, y;
    Point() {}
    Point(double _x, double _y)
    {
        x = _x; y = _y;
    }
    Point operator +(const Point &b)const
    {
        return Point(x + b.x, y + b.y);
    }
    Point operator -(const Point &b)const
    {
        return Point(x - b.x, y - b.y);
    }
    double operator ^(const Point &b)const
    {
        return x * b.y - y * b.x;
    }
    Point operator *(const double &b)const
    {
        return Point(x * b , y * b);
    }
    double operator *(const Point &b)const
    {
        return x * b.x + y * b.y;
    }
    void transXY(double B)
    {
        double tx = x, ty = y;
        x = tx * cos(B) - ty * sin(B);
        y = tx * sin(B) + ty * cos(B);
    }
    double distance(Point bb)
    {
        return sqrt((x - bb.x) * (x - bb.x) + (y - bb.y) * (y - bb.y));
    }
    void show()
    {
        cout << fixed << setprecision(6) << x << "," << y << endl;
    }
};
Point Yuanxin(Point &a, Point &b, Point &c)   //(已知三點求圓心座標)
{
    Point q;
    q.x = ((c.y - a.y) * (c.y - b.y) * (b.y - a.y) + (a.x * a.x - b.x * b.x) * (c.y - a.y) - (a.x * a.x - c.x * c.x) * (b.y - a.y)) / (2 * ((c.y - a.y) * (a.x - b.x) - (a.x - c.x) * (b.y - a.y)));
    q.y = ((c.x - a.x) * (c.x - b.x) * (b.x - a.x) + (a.y * a.y - b.y * b.y) * (c.x - a.x) - (a.y * a.y - c.y * c.y) * (b.x - a.x)) / (2 * ((c.x - a.x) * (a.y - b.y) - (a.y - c.y) * (b.x - a.x)));
    return q;
}
int n;
Point a[maxn];
std::vector<pll> v;
int main()
{
#if DEBUG_Switch
    freopen("C:\\code\\input.txt", "r", stdin);
#endif
    //freopen("C:\\code\\output.txt","w",stdout);
    n = readint();
    repd(i, 1, n)
    {
        a[i].x = readint();
        a[i].y = readint();
    }
    Point o = Point(0, 0);
    repd(i, 1, n)
    {
        repd(j, i + 1, n)
        {
            if (abs((o - a[i]) ^ (o - a[j])) < eps)
            {
                continue;
            }
            Point center = Yuanxin(o, a[i], a[j]);
            v.pb(mp((ll)(1ll * center.x * 1000000), (ll)(1ll * center.y * 1000000)));
        }
    }
    sort(ALL(v));
    int ans = 0;
    int cnt = sz(v);
    int num = 1;
    for (int i = 1; i < cnt; ++i)
    {
        if (v[i] == v[i - 1])
        {
            num++;
        } else
        {
            num = 1;
        }
        ans = max(ans, num);
    }

    ans = ans * 2;
    int temp;
    repd(i, 1, n)
    {
        if (i * i - i == ans)
        {
            temp = i;
        }
    }
    printf("%d\n", temp );
    return 0;
}



C-Cover the Tree

思路:

找到這樣一個節點,使其刪掉該點後生成的眾多子樹中葉子節點分配的最均衡,即眾多子樹中葉子節點最大的個數儘量小。(可以用求重心的方法變形一下求得)

然後以該節點為根節點,將不同子樹的葉子節點分配在眾多集合中,每次選擇2個size最大的集合,將其兩個集合中任一一點進行相連成鏈,直到所有集合的size都為0,或者只剩下一個size為1的集合(這樣情況只需要把該葉子和樹根連線一下即可。)

程式碼:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x)  if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '\n' : ' ');}}
void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '\n' : ' ');}}
const int maxn = 300010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 1
vector<int> tree[maxn];
int n, minNode, minBalance;
//minNode當前重心節點
//minBalance當前重心節點的最大子樹節點個數
int d[maxn];
//d[i]表示以i為根的子樹節點個數
int leaf = 0;
void dfs(int u, int fa) {
    if (sz(tree[u]) == 1)
        d[u] = 1; //節點本身
    else
        d[u] = 0;
    int maxSub = 0, size = tree[u].size(); //maxSub為節點u的最大子樹節點個數
    for (int i = 0; i < size; i++) {
        int v = tree[u][i];
        if (v != fa) {
            dfs(v, u);
            d[u] += d[v];
            maxSub = max(maxSub, d[v]);
        }
    }
    maxSub = max(maxSub, leaf - d[u]);
    if (maxSub < minBalance) {
        minNode = u;
        minBalance = maxSub;
    }
}
set<int> st[maxn];
int tot = 0;
void dfs2(int x, int pre, int id)
{
    if (sz(tree[x]) == 1)
    {
        tot++;
        st[id].insert(x);
        return ;
    } else
    {
        for (auto &y : tree[x])
        {
            if (pre != y)
                dfs2(y, x, id);
        }
    }
}
struct node
{
    int val;
    int id;
    node() {

    }
    node(int vv, int ii)
    {
        val = vv;
        id = ii;
    }
    bool operator< ( node b) const
    {
        if (val == b.val)
        {
            return id < b.id;
        } else
        {
            return val > b.val;
        }
    }
};
int main() {
    // freopen("C:\\code\\input.txt", "r", stdin);
    cin >> n;
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        tree[u].push_back(v);
        tree[v].push_back(u);
    }
    if (n == 1)
    {
        printf("0\n");
        return 0;
    }
    minNode = 0;
    minBalance = 0x3f3f3f3f;
    int s;
    repd(i, 1, n)
    {
        if (sz(tree[i]) == 1)
        {
            leaf++;
        } else
        {
            s = i;
        }
    }
    dfs(s, s);
    int r = 0;
    for (auto &y : tree[minNode])
    {
        dfs2(y, minNode, ++r);
    }
    std::vector<pii> v;
    set<node> q;
    int l = 1;
    repd(i, l, r)
    {
        q.insert(node(st[i].size(), i));
    }
    while (q.size() > 0)
    {
        if (q.size() == 1)
        {
            int id = (*q.begin()).id;
            v.pb(mp(*st[id].begin(), minNode));
            st[id].erase(st[id].begin());

            std::vector<int> temp;
            temp.clear();
            for (auto now : st[id])
            {
                temp.pb(now);
            }
            int m = sz(temp);
            for (int i = 0; i < m; i += 2)
            {
                v.pb(mp(temp[i], temp[i + 1]));
            }
            // printf("? \n");
            break;
        } else
        {
            int i = (*q.begin()).id;
            q.erase(q.begin());
            int id = (*q.begin()).id;
            q.erase(q.begin());

            int x = *st[i].begin();
            st[i].erase(st[i].begin());

            int y = *st[id].begin();
            st[id].erase(st[id].begin());

            v.pb(mp(x, y));
            if (sz(st[i]) > 0)
                q.insert(node(st[i].size(), i));
            if (sz(st[id]) > 0)
                q.insert(node(st[id].size(), id));

        }
    }
    printf("%d\n", sz(v) );
    for (auto &Y : v)
    {
        printf("%d %d\n", Y.fi, Y.se );
    }
    return 0;
}

Duration

思路:

直接將時間點都轉成用秒數表示的時間點,求差的絕對值即可。

程式碼:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x)  if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '\n' : ' ');}}
void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '\n' : ' ');}}
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
char s[maxn];

int main()
{
#if DEBUG_Switch
	freopen("C:\\code\\input.txt", "r", stdin);
#endif
	//freopen("C:\\code\\output.txt","w",stdout);
	scanf("%s", s + 1);
	ll a = ((s[1] - '0') * 10 + (s[2] - '0')) * 3600 + ((s[4] - '0') * 10 + (s[5] - '0')) * 60 + ((s[7] - '0') * 10 + (s[8] - '0'));
	scanf("%s", s + 1);
	ll b = ((s[1] - '0') * 10 + (s[2] - '0')) * 3600 + ((s[4] - '0') * 10 + (s[5] - '0')) * 60 + ((s[7] - '0') * 10 + (s[8] - '0'));
	printf("%lld\n", abs(b - a));
	return 0;
}



I -Interval

題意:

給定一個\([1,n]\)的區間,

設當前區間為\([l,r]\)每一次操作可以使其改變為:\([l+1,r],[l,r-1],[l-1,r](l>1),[l,r+1](r<n)\)

但是我們不能將區間改變為\([l,r],l=r\),為了達到這麼限制,你可以禁掉一些區間時的收縮,同時需要付出一些成本,問你最少需要付出多少成本?如果給定的可禁操作不足以讓區間退化成點,那麼輸出-1.

思路:

我們可以將每一個區間\([l,r]\)轉化成\((l,r)\)二維平面網格上的一個點,圖的左下角節點其實為無意義的節點。

我們知道每個點可以轉向區間中與其相鄰的節點,網格中的邊初始全部設為無窮大,然後對於可以禁止掉的邊,我們將邊權轉為禁止該邊的成本。

然後問題就轉化為,從上圖中的有綠點的邊集合中選出一個子集,使其刪除該子集後點\((1,n)\)無法移動到點\((i,i),i\in [1,n]\),同時要求子集的邊權總和儘可能的小。

顯然,這是一個網路流求最小割的問題。

根據資料範圍觀察, 一共會有\((n-1)*n/2\)個節點,跑網路流肯定是會超時的。

平面圖定義:一個可以在二維平面上讓所有邊互不相交的圖。

對偶圖定義:平面圖中的面為節點,邊轉為連線不同面的邊,邊權不變。

又發現該網格圖是一個平面圖,那麼平面圖的最小割問題可以轉成對偶圖的最短路問題。

對偶圖如下圖中的紫色的網路:

可以發現該網路的任意一個\(S->T\)的路徑對應的平面圖邊集合一定是一個割。

然後求一下\(S->T\)的最短路即可。

程式碼:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x)  if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '\n' : ' ');}}
void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '\n' : ' ');}}
const int maxn = 510;
const ll inf = 1e18;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
int n, m;
ll L_cost[maxn][maxn];
ll R_cost[maxn][maxn];
inline int getid(int x, int y)
{
    return (x - 1) * n + y;
}
struct node
{
    int to;
    ll val;
    node() {}
    node(int tt, ll vv) {
        to = tt;
        val = vv;
    }
    bool operator < (const node & b) const {
        return val > b.val;
    }
    void show()
    {
        cout << to << " " << val << endl;
    }
};
std::vector<node> e[maxn * maxn];
ll dis[maxn * maxn];
void addedge(int a, int b, ll v)
{
    assert(a >= 0 && b >= 0 && v >= 0);
    e[a].push_back(node(b, v));
    e[b].push_back(node(a, v));
}
bool vis[maxn * maxn];
void init(int n)
{
    for (int i = 0; i <= n; ++i)
    {
        dis[i] = 1e18;
        vis[i] = 0;
    }
}
priority_queue<node> heap;
void dijkstra(int strat)
{
    assert(strat >= 0 && strat < maxn );
    init(n * n + 1);
    dis[strat] = 0ll;
    heap.push(node(strat, 0ll));
    node temp;
    while (!heap.empty())
    {
        temp = heap.top();
        heap.pop();
        assert(temp.to >= 0 && temp.to < maxn * maxn );
        if (vis[temp.to])
        {
            continue;
        } else
        {
            vis[temp.to] = 1;
        }
        // cout << sz(e[temp.to]) << endl;
        for (auto & x : e[temp.to])
        {
            // x.show();
            assert(x.to >= 0 && x.to < maxn * maxn );
            assert(x.val > 0);
            if (dis[temp.to] + x.val < dis[x.to])
            {
                dis[x.to] = dis[temp.to] + x.val;
                heap.push(node(x.to, dis[x.to]));
            }
        }
    }
}
int s, t;
int main()
{
#if DEBUG_Switch
    freopen("C:\\code\\input.txt", "r", stdin);
#endif
    //freopen("C:\\code\\output.txt","w",stdout);
    n = readint();
    m = readint();
    repd(i, 1, n)
    {
        repd(j, 1, n)
        {
            L_cost[i][j] = inf;
            R_cost[i][j] = inf;
        }
    }
    repd(i, 1, m)
    {
        int l, r, val;
        char op;
        scanf("%d %d %c %d", &l, &r, &op, &val);
        if (op == 'L')
        {
            L_cost[l][r] = val;
        } else
        {
            R_cost[l][r] = val;
        }
    }
    s = 0;
    t = n * n;
    repd(i, 1, n)
    {
        repd(j, i + 1, n)
        {
            if (i == 1)
            {
                addedge(s, getid(i, j), R_cost[i][j]);
            } else
            {
                addedge(getid(i - 1, j), getid(i, j), R_cost[i][j]);
            }
            if (j == n)
            {
                addedge( getid(i, j), t, L_cost[i][j]);
            } else
            {
                addedge( getid(i, j), getid(i, j + 1), L_cost[i][j]);
            }
        }
    }
    dijkstra(s);
    printf("%lld\n", dis[t] >= inf ? -1 : dis[t] );

    return 0;
}



k -Keyboard Free

思路:

首先審完題面應該注意到,該題目要求的精度很小。

\(C_1,C_2,C_3\)為半徑依次增大的圓。

因為圓是完全對稱的圖形,可以得知,對於\(C_1\)上任意一個點得到的期望三角形面積是相同的。

所以我們可以固定點\(\mathit A\)\(C_1\)上,因為對精度要求較低,我們可以列舉點\(B\in C_2\)

然後對\(C\in C_3\)進行積分得到確定的點\(A,B\)構成的三角形面積期望值,對於列舉的每一個點\(\mathit B\)得到的期望值求和,然後除以列舉的次數即可得到最終的期望。

至於具體可以這麼做的原因是因為變動角度\(\alpha\)和三角形面積函式\(S=F(\alpha)\)的函式圖形是光滑連續的函式,這樣分小段求解的面積的平均值就和微分後積分求得的面積相差很小。

變數關係:

設列舉的點\(\mathit B\)與圓心所在的水平軸的夾角為\(\mathit i\)

\(x=r_2*cos(i)-r_1\)

\(y=r_2*sin(i)\)

\(L=sqrt(x^2+y^2)\)

\(H=\frac{y}{L}*r_1\)

\(\alpha=asin(H/r_3)\)

接著通過積分求出 \(C\)點運動時這個三角形的期望高,我們將其分成三部分求解即可。

程式碼:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x)  if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '\n' : ' ');}}
void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '\n' : ' ');}}
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
int r[4];
double si[1050];
double co[1050];
const double pi = acos(-1);
const int base = 500;
void init()
{
    double p = pi * 2;
    repd(i, 0, base)
    {
        si[i] = sin(p / base * i);
        co[i] = cos(p / base * i);
    }
}
void solve()
{
    double ans = 0;
    repd(i, 1, base)
    {
        double x = r[2] * co[i];
        double y = r[2] * si[i];
        double L = sqrt((x - r[1]) * (x - r[1]) + y * y);
        double h = y / L * r[1];
        double alpha = asin(h / r[3]);
        double eh = (4.0 * r[3] * cos(alpha) + 4.0 * alpha * h) / (2.0 * pi);
        ans += eh * L / 2.0;
    }
    ans /= base;
    printf("%.1f\n", ans );
}
int main()
{
#if DEBUG_Switch
    freopen("C:\\code\\input.txt", "r", stdin);
#endif
    //freopen("C:\\code\\output.txt","w",stdout);
    init();
    int t;
    t = readint();
    while (t--)
    {
        repd(i, 1, 3)
        {
            r[i] = readint();
        }
        sort(r + 1, r + 4);
        solve();
    }

    return 0;
}