2021年度训练联盟热身训练赛第三场(EFL除外)

2021年度训练联盟热身训练赛第三场(EFL除外)

A Circuit Math(stack)

后缀表达式,用stack解决

AC代码:

#include <bits/stdc++.h>

using namespace std;

map<char, int> mp;
stack<int> st;
char c, d;
int n, len;
int a, b;
string s;

int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; ++i)
    {
        scanf(" %c", &d);
        c = 'A' + i;
        if(d == 'T')    mp[c] = 1;
        else    mp[c] = 0;
    }
    getchar();
    getline(cin, s);
    len = s.size();
    for(int i = 0; i < len; i += 2)
    {
        if(s[i] >= 'A' && s[i] <= 'Z')  st.push(mp[s[i]]);
        else if(s[i] == '*')
        {
            a = st.top();
            st.pop();
            b = st.top();
            st.pop();
            st.push(a & b);
        }
        else if(s[i] == '+')
        {
            a = st.top();
            st.pop();
            b = st.top();
            st.pop();
            st.push(a | b);
        }
        else if(s[i] == '-')
        {
            a = st.top();
            st.pop();
            st.push(!a);
        }
    }
    if(st.top())    putchar('T');
    else putchar('F');
    return 0;
}

B Diagonal Cut(规律)

求两数的gcd,然后约分,约分后得到两个数,若两个数都是奇数,则答案是gcd,否则答案为0

AC代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000 + 7
#define endl '\n'
//#define mod 571373;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);
inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

ll gcd(ll a, ll b)
{
    if(b) return gcd(b, a % b);
    else return a;
}
ll n, m;
int main(){
    cin>>n>>m;
    ll g = gcd(n, m);
    ll x = n / g;
    ll y = m / g;
    if(x % 2 == 1 && y % 2 == 1)cout<<g<<endl;
    else cout<<0<<endl;
    cout<<gcd(n  , m);
//    ll maxn = max(n, m);
//    ll minx = min(n, m);
//    if(maxn == minx)cout<<minx<<endl;
//    else if(maxn % minx == 0){
//        if(maxn / minx % 2 == 1)cout<<minx<<endl;
//        else cout<<0<<endl;
//    }
//    else {
//        ll x = m / gcd(n, m);
//        ll ans = m / x;
//        cout<<ans<<endl;
//    }
//
    return 0;
}

C Gerrymandering

背景是美国总统大选,先输入两个数n,m代表有n次计票,有m个州参加投票,如果一共投了300票,那么谁先得到151张谁就赢了,假设拜登得了200票,建国同志得了100票,那么拜登得到票种有49张是无效的(因为只需要151张就可以惹),建国同志这100张都是无效的,然后有个量好像叫什么效率,公式是这样的在这里插入图片描述wa,wb分别代表拜登和建国同志得到的无效票,v代表总票数。
之后有n行输入,每行三个数,第一个代表这是哪个州,后面两个数分别是拜登和建国同志的的票。
对于输出,要求输出m + 1行,第i行输出三个东西,第一个是字符,对于这个州来说,拜登赢了输出A,建国同志赢了输出B,然后分别输出它们两个所浪费的票,最后一行输出那个效率。
看懂题之后很简单,就是题目太长了。。。

AC代码:

#include <bits/stdc++.h>

using namespace std;

int p, D;
struct node
{
    int a, b;
    int aa, bb;
} ar[1050];
int wa, wb, v;
int d, x, y, st;

int main()
{
    scanf("%d%d", &p, &D);
    for(int i = 1; i <= p; ++i)
    {
        scanf("%d%d%d", &d, &x, &y);
        ar[d].a += x;
        ar[d].b += y;
        v += x;
        v += y;
    }
    for(int i = 1; i <= D; ++i)
    {
        st = (ar[i].a + ar[i].b) / 2 + 1;
        if(ar[i].a >= st)
        {
            printf("A ");
            ar[i].aa = ar[i].a - st;
            ar[i].bb = ar[i].b;
            printf("%d %d\n", ar[i].aa, ar[i].bb);
        }
        else
        {
            printf("B ");
            ar[i].aa = ar[i].a;
            ar[i].bb = ar[i].b - st;
            printf("%d %d\n", ar[i].aa, ar[i].bb);
        }
        wa += ar[i].aa;
        wb += ar[i].bb;
        //cout << st << endl;
    }
    double w = fabs(double(wa) - double(wb));
    double vv = double(v);
    double ans = w / vv;
    printf("%.10lf", ans);
    return 0;
}

D题 签到题,过

G Research Productivity Index(期望dp)

说这个人写了n票论文,有的交上去能过,有的不能过 ,有一个量叫研究效率指数,它的值是a^(a/s),a代表过的论文,s代表一共交了多少篇,这个人知道每篇论文过的概率,并且它会明智的提交论文,求他这个研究效率指数期望的最大值。
分析:
这个题的题意不是很好理解,首先要求的是期望的最大值,就说明要在不同条件下求好几个研究效率指数,这个不同的条件就是,提交不同的篇数,他又是明智的所以她一定会交通过可能最大的那几篇,比如交了3篇,那他可能过0,1,2,3篇,这对应不同的概率,也对应不同的a值,所以有一个期望。
剩下的问题在于怎么求期望,我们需要知道不同的a^(a/s)对应的概率,如交了3篇,我们需要求出过了0,1,2,3篇的概率,而这需要动态规划,比如交了i篇过了j篇的概率可以由交了i - 1篇过了j篇的概率和交了i - 1篇过了j篇的概率求出。状态转移方程如下:

dp[i][j] = dp[i - 1][j - 1] * ar[i] * 1.0 / 100 + dp[i - 1][j] * (100 - ar[i]) * 1.0 / 100;

除此之外,还需要考虑初始化和边界条件,初始化dp[0][0] = 1,交了0份,过了0分的概率是1,还有一个后界就是交了i篇过了i篇的概率,有一种情况是由交了i - 1篇过了i篇推过来的,很明显这是不可能的,而dp[i - 1][i]一定是0,所以也不会对答案造成影响。
接下来就是分别求出交1~n篇的期望,然后取个最大值即可
AC代码:

#include <bits/stdc++.h>

using namespace std;

int n;
double ar[105];
double ans, temp;
double dp[105][105];

bool cmp(double a, double b)
{
    return a > b;
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%lf", &ar[i]);
    sort(ar + 1, ar + n + 1, cmp);
    dp[0][0] = 1;
    for(int i = 1; i <= n; ++i) dp[i][0] = dp[i - 1][0] * (100 - ar[i]) / 100.0;
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= i; ++j)
        {
            dp[i][j] = dp[i - 1][j - 1] * ar[i] * 1.0 / 100 + dp[i - 1][j] * (100 - ar[i]) * 1.0 / 100;
        }
    }
    for(int i = 1; i <= n; ++i)
    {
        temp = 0;
        for(int j = 1; j <= i; ++j)
        {
            temp += (pow(j, j * 1.0 / i) * dp[i][j]);
        }
        ans = max(ans, temp);
    }
    printf("%.9lf\n", ans);
    return 0;
}

​I Slow Leak(最短路dijstra & floyd)

题意:
有n个点,m条边,t个加油站,还有一个d代表加一次油车最多能走多远,然后输入t个数,代表这t个加油站,然后m行,每行三个数u,v,w代表u和v之间有一条长度为w的路。求出点1到点n的最短路。注意限制条件d,单词开车不加油最多走的距离是d。然后能走到输出最短路,走不到输出stuck
分析:
先跑一篇floyd,得到任意两点的最短路,然后考虑到图中这n个点,有t + 2个点是特殊的(起始点应该不会同时是加油站),这t+2个点是t个加油站和起始点,我们可以建一张只有这t+2个点的图,判断这t +2个点种的任意一个点与其他t + 1个点的最短路是否小于等于d,如果小于就连边。这样就建完图了,这样建的图就不需要考虑那个d的限制了.
AC代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

int n, m, t, tot;
int u, v;
ll w;
ll d;
ll mp[505][505];
ll dis[505];
int head[505];
bool vis[505];
int tt[505];

struct node
{
    int v, w, ne;
} edge[250050];

struct node1
{
    int l, pos;
    bool operator < (const node1 b) const
    {
        return l > b.l;
    }
};
priority_queue<node1> q;

void Init()
{
    tot = 0;
    memset(mp, 0x3f, sizeof(mp));
    memset(head, -1, sizeof(head));
    memset(edge, -1, sizeof(edge));
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, 0, sizeof(vis));
}

void addedge(int u, int v, int w)
{
    edge[++tot].v = v;
    edge[tot].w = w;
    edge[tot].ne = head[u];
    head[u] = tot;
}

void floyd() {
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                mp[i][j]=min(mp[i][j], mp[i][k] + mp[k][j]);
}

void dijkstra()
{
    struct node1 now, next;

    dis[1] = 0;

    now.l = 0, now.pos = 1;
    q.push(now);

    while(!q.empty())
    {
        now = q.top();
        q.pop();

        if(vis[now.pos]) continue;
        vis[now.pos] = 1;

        for(int i = head[now.pos]; i != -1; i = edge[i].ne)
        {
            next.pos = edge[i].v;
            if(dis[next.pos] > dis[now.pos] + edge[i].w)
            {
                dis[next.pos] = dis[now.pos] + edge[i].w;
                next.l = dis[next.pos];
                q.push(next);
            }
        }
    }
}

int main()
{
    Init();
    scanf("%d%d%d%lld", &n, &m, &t, &d);
    for(int i = 1; i <= t; ++i) scanf("%d", &tt[i]);
    tt[++t] = 1, tt[++t] = n;
    for(int i = 1; i <= m; ++i)
    {
        scanf("%d%d%lld", &u, &v, &w);
        mp[u][v] = mp[v][u] = w;
    }
    floyd();
    for(int i = 1; i <= t + 2; ++i)
    {
        for(int j = i + 1; j <= t + 2; ++j)
        {
            if(mp[tt[i]][tt[j]] <= d)
            {
                addedge(tt[i], tt[j], mp[tt[i]][tt[j]]);
                addedge(tt[j], tt[i], mp[tt[i]][tt[j]]);
            }
        }
    }
    dijkstra();
    if(dis[n] >= 0x3f3f3f3f3f3f3f3f)    printf("stuck\n");
    else    printf("%d\n", dis[n]);
    //cout << dis[n] << endl;
    return 0;
}



J Stop Counting!(前缀和/后缀和)

题意:
给你一坨数,可以删掉连续的k(k可取1~n)个数,请你进行一次删除操作,使得剩下的数的平均数最大。
分析:
这个题,弄明白一个问题即可,就是这又两坨数,一坨的平均数是a,另一坨的平均数是b,把这两坨数合在一起的话平均数绝对不会大于max(a,b),所以没必要在中间删除k个数,就是在开头删除一坨数,或者在结尾删除一坨数,所以做法是求前缀和以及后缀和,然后遍历一遍前缀和数组和后缀和数组,求平均值并取max
AC代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

int n;
ll ar[1000050], br[1000050], cr[1000050];
double ans, ans1, ans2;

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%lld", &ar[i]);
        br[i] = br[i - 1] + ar[i];
    }
    for(int i = n; i > 0; --i)
    {
        cr[i] = cr[i + 1] + ar[i];
        ans2 = (double)cr[i] / (n - i + 1);
        ans1 = (double)br[i] / i;
        ans = max(ans, max(ans1, ans2));
    }
    printf("%.10lf\n", ans);
    return 0;
}

K Summer Trip(字符串构造)

按照他说的构造即可,跑两层for循环(不会超时,因为第二层跑不了太多次,会break的),然后可以预处理优化一下,对于字符串aabbbdddfff,预处理为abdf。
AC代码:

#include <bits/stdc++.h>

using namespace std;

string s;
string ss;
char la;
int len, ans;
bool vis[30];

int main()
{
    cin >> s;
    len = s.size();
    la = s[0];
    ss += la;
    for(int i = 1; i < len; ++i)
    {
        if(la == s[i])  continue;
        else    ss += s[i];
        la = s[i];
    }
    len = ss.size();
    for(int i = 0; i < len; ++i)
    {
        memset(vis, 0, sizeof(vis));
        for(int j = i + 1; j < len; ++j)
        {
            if(ss[j] == ss[i])  break;
            else if(!vis[(int)ss[j] - 96])
            {
                ans++;
                vis[(int)ss[j] - 96] = 1;
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

M Zipline(数学 /思维/二分)

在这里插入图片描述

最小值,不用说
那个最大最小值,就算当时没看懂题,
1.应该瞎验证样例,也能发现是一个点对称下去
2.求出表达式,既然是最值,求导,二分导数等于0的点,根本不用管这是个极大值还是极小值,直接带就行,反正要么是导数为0点,要么是端点。
3.应该意识到这是一个特殊的点,两边的点都应该比这个点处取值大或小,所以就是看不懂题应该要瞎猜到袜,呜呜呜 ~~~

AC代码:
对称做法:

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define inf 0x3f3f3f3f
#define MAX 1000000 + 7
#define endl '\n'
//#define mod 571373;
typedef  long long ll ;
//不开longlong见祖宗!
//ios::sync_with_stdio(false);
//cin.tie(0); cout.tie(0);
inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;
        ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

int n;
double a, b, c, d, minx, maxn;

int main(){
    cin>>n;
    while (n--) {
        cin>>a>>b>>c>>d;
        minx = sqrt(a * a + (b - c)*(b - c));
        maxn = sqrt(a * a + (b + c - 2 * d) * (b + c - 2 * d));
        printf("%.8f %.8f\n",minx, maxn);
    }
}

函数求导做法:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

int main() {
    int n;
    cin >> n;
    while (n--) {
        ll w, g, h, r; // 注意数据范围,平方会爆int
        cin >> w >> g >> h >> r;
        // 求长度的最小值:l = min(g,h),且人处于高度较低处
        double mi = sqrt((w * w) + (h - g) * (h - g));

        // 求长度的最大值: l = r,二分找出导数为0的点
        g = g - r;
        h = h - r;
        double L = 0, R = w;
        while (R - L > 1e-8) // 设置精度一般比题目要求多两位
        {
            double x = (R + L) / 2;
            double f = x / sqrt(g * g + x * x) - (w - x) / sqrt(h * h + (w - x) * (w - x));
            if (f < 0) L = x;
            else R = x;
        }
        // 带回原方程求解
        double ma = sqrt(g * g + L * L) + sqrt(h * h + (w - L) * (w - L));
        printf("%.8lf %.8lf\n", mi, ma);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值