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;
}



posted @ 2020-07-16 11:42  茄子Min  阅读(265)  评论(0编辑  收藏  举报