zoukankan      html  css  js  c++  java
  • 天天快乐编程2020年OI集训队 训练9题解

    本次主要是分治以及最短路。一定要注意赛后的补题,把自己会的题做完了,赛后不管了,那么这场训练毫无意义,要去积极尝试自己不会的,不懂的问老师。

    1.4839: 麦森数

    NOIP2003普及组T1
    2^p与2^p-1有着相同的位数,2的p次方末位一定不为0,减1位数不会改变,那我们可以直接求2^p的位数,位数为log10(2*p)+1
    然后就是求后500位了,裸的高精度快速幂
    快速幂也是分治思想,把它和二分联系起来

    #include<bits/stdc++.h>
    using namespace std;
    int a[510]={2};
    #define M 500
    void mul()
    {
        for(int i=0;i<M;i++)
            a[i]*=2;
        for(int i=0;i<M;i++)
          a[i+1]+=a[i]/10,a[i]%=10;
    }
    void square()
    {
        int b[510]={0};
        for(int i=0;i<M;i++)
            for(int j=0;j<M;j++)
                if(i+j<M)
                    b[i+j]+=a[i]*a[j];
        for(int i=0;i<M;i++)
          b[i+1]+=b[i]/10,b[i]%=10;
        for(int i=0;i<M;i++)
            a[i]=b[i];
    
    }
    void quickmi(int x)
    {
        if(x/2>1) quickmi(x/2);
        square();
        if(x%2) mul();
    }
    int main()
    {
        int p;
        scanf("%d",&p);
        printf("%d
    ",(int)(log10(2.0)*p)+1);
        quickmi(p);
        a[0]--;
        for(int i=M-1;i>=0;i--)
            printf("%d",a[i]);
    }
    

    2.6020: 扫雷游戏

    NOIP2015 普及组T2
    这个题目不需要用到分治,我们直接直接按照雷进行循环,模拟就行了
    注意下标不要越界啊

    #include<bits/stdc++.h>
    using namespace std;
    //有雷为1,无雷为0 
    bool a[105][105];
    int main()
    {
        int n,m;
        char tmp;
        cin>>n>>m; 
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++) 
            {
                cin>>tmp;
                //如果是地雷就将这个点设为1
                if(tmp=='*') a[i][j]=1; 
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(a[i][j]==1)
                {
                    printf("*"); //如果是地雷不用输出数字 
                }
                else
                {
                    printf("%d",a[i+1][j+1]+a[i+1][j-1]+a[i+1][j]+a[i][j+1]+a[i][j-1]+a[i-1][j+1]+a[i-1][j]+a[i-1][j-1]);
                }
            }
            printf("
    ");
        }
        return 0;
    }
    

    3.6272: 龙虎斗

    NOIP2018 普及组T2
    给出n个数,再给出一个m位置,定义a和b,(m不属于a或b):a为1~m-1个数每个数用这个数到m的距离乘这个数的积之和,b则为m+1~n中再在这n个每个数用这个数到m的距离乘这个数的积之和,然后在其中一个位置(p1)加入了一个数(s1),现在再给你一个数(s2),求这个数加在哪一个位置能让a和b的差最小(加上去这个数的计算方法和之前相同)
    我们可以枚举举1~m-1(即a区间)内的位置去找最小值,当然记得开ll,十年OI一场空,不开long long见祖宗。

    #include <bits/stdc++.h>
    using namespace std;
    long long a[100005], s1, s2, sum2, sum1, minn;
    int m, n, p1, ans;
    int main()
    {
        cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        cin >> m >> p1 >> s1 >> s2;
        a[p1] += s1;
        for (int i = 1; i < m; i++)
            sum1 += a[i] * (m - i);
        for (int i = m + 1; i <= n; i++)
            sum2 += a[i] * (i - m);
        minn = abs(sum1 - sum2);
        ans = m;
        for (int i = 1; i < m; i++)
            if (abs(sum1 + s2 * (m - i) - sum2) < minn)
            {
                minn = abs(sum1 + s2 * (m - i) - sum2);
                ans = i;
            }
        for (int i = m + 1; i <= n; i++)
            if (abs(sum2 + s2 * (i - m) - sum1) < minn)
            {
                minn = abs(sum2 + s2 * (i - m) - sum1);
                ans = i;
            }
        cout << ans;
    }
    

    4.4866: 瑞士轮

    NOIP2011普及组T3
    这个题有一定难度
    每组比赛的胜者:赛前,总分是按降序排的;获胜后都得1分,仍是降序;
    每组比赛的负者:赛前,总分是按降序排的;不得分,仍是降序。
    先按初始分数排序,然后按分数高低两人一组比赛;
    胜者入队A,负者入队B。这样A、B自身仍是有序的;只需进行合并操作即可。
    这不就是归并排序吗?说实话,这个题确实高。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 200005;
    struct point
    {
        int num, id, w;
        bool operator<(const point &tmp) const
        {
            if (num != tmp.num)
                return num > tmp.num;
            return id < tmp.id;
        }
    } a[N >> 1], b[N >> 1], tmp[N];
    int n, r, q;
    void merge()
    {
        int i = 1, j = 1, k = 1;
        while (i <= n && j <= n)
        {
            if (a[i].num > b[j].num || a[i].num == b[j].num && a[i].id < b[j].id)
                tmp[k++] = a[i++];
            else
                tmp[k++] = b[j++];
        }
        while (i <= n)
            tmp[k++] = a[i++];
        while (j <= n)
            tmp[k++] = b[j++];
    }
    int main()
    {
        scanf("%d%d%d", &n, &r, &q);
        for (int i = 1; i <= 2 * n; i++)
            scanf("%d", &tmp[i].num), tmp[i].id = i;
        for (int i = 1; i <= 2 * n; i++)
            scanf("%d", &tmp[i].w);
        sort(tmp + 1, tmp + 2 * n + 1);
        for (int t = 1; t <= r; t++)
        {
            int cnt = 1;
            for (int i = 1; i < 2 * n; i += 2)
            {
                if (tmp[i].w > tmp[i + 1].w)
                    a[cnt] = tmp[i], b[cnt] = tmp[i + 1], a[cnt++].num++;
                else
                    a[cnt] = tmp[i + 1], b[cnt] = tmp[i], a[cnt++].num++;
            }
            merge();
        }
        printf("%d
    ", tmp[q].id);
        return 0;
    }
    

    5.5914: 铺设道路

    NOIP2018提高组Day1T1
    它就是一个贪心。
    题目里给的样例是4,3,2,5,3,5;
    可以选择一个区间进行“填坑”操作;
    所以我们的贪心策略是:
    若a[i]>a[i-1],计数器sum+=a[i]-a[i-1];
    那么为什么这样贪心是对的呢?
    贪心证明
    假设现在有一个坑,但旁边又有一个坑。
    你肯定会选择把两个同时减1;
    那么小的坑肯定会被大的坑“带着”填掉。
    大的坑也会减少a[i]-a[i-1]的深度,可以说是“免费的”;
    所以这样贪心是对的;

    #include <bits/stdc++.h>
    using namespace std;
    int a[100001];
    
    int main()
    {
        int n;
        cin >> n;
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &a[i]);
        }
        int sum = 0;
        for (int i = 1; i <= n; ++i)
        {
            if (a[i] > a[i - 1])
            {
                sum += a[i] - a[i - 1];
            }
        }
        printf("%d
    ", sum);
    }
    

    6.4811: 最优贸易

    NOIP2009提高组T2
    可以考虑一下单源最短路径。 假设我们是阿龙的话,当然会在路径上选择最便宜的地方买物品,最贵的地方售出物品。
    如果对Dijkstra的更新方式进行修改,就可以求出从源点到每一个点购入的最便宜价格。
    但是怎么搞呢,两次Dijkstra,再枚举ans=max(售出价格[i]-购入价格[i])即可求出答案。当然第二次Dijkstra要求进行在反图上

    #include <bits/stdc++.h>
    using namespace std;
    const int M = 500010;
    const int N = 100010;
    int dist1[N], dist2[N], vis1[N], vis2[N];
    vector<int> e1[N], e2[N];
    struct pt1
    {
        int u, dis;
        bool operator>(const pt1 &t) const { return dis > t.dis; }
    } p1[N];
    struct pt2
    {
        int u, dis;
        bool operator<(const pt2 &t) const { return dis < t.dis; }
    } p2[N];
    priority_queue<pt1, vector<pt1>, greater<pt1>> q1;
    priority_queue<pt2, vector<pt2>, less<pt2>> q2;
    int n, m, money[N];
    void dj1()
    {
        for (int i = 1; i <= n; i++)
        {
            dist1[i] = money[i];
        }
        q1.push((pt1){1, dist1[1]});
        while (!q1.empty())
        {
            int u = q1.top().u;
            q1.pop();
            if (vis1[u])
                continue;
            vis1[u] = 1;
            for (int i = 0; i < e1[u].size(); i++)
            {
                int v = e1[u][i];
                if (dist1[v] > dist1[u])
                {
                    dist1[v] = dist1[u];
                    q1.push((pt1){v, dist1[v]});
                }
                if (vis1[v] == 0)
                    q1.push((pt1){v, dist1[v]});
            }
        }
    }
    void dj2()
    {
        for (int i = 1; i <= n; i++)
            dist2[i] = money[i];
        q2.push((pt2){n, dist2[n]});
        while (!q2.empty())
        {
            int u = q2.top().u;
            q2.pop();
            if (vis2[u])
                continue;
            vis2[u] = 1;
            for (int i = 0; i < e2[u].size(); i++)
            {
                int v = e2[u][i];
                if (dist2[v] < dist2[u])
                {
                    dist2[v] = dist2[u];
                    q2.push((pt2){v, dist2[v]});
                }
                if (vis2[v] == 0)
                    q2.push((pt2){v, dist2[v]});
            }
        }
    }
    int main()
    {
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
            cin >> money[i];
        for (int i = 1; i <= m; i++)
        {
            cin >> u >> v >> op;
            if (op == 1)
                e1[u].push_back(v), e2[v].push_back(u);
            else
            {
                e1[u].push_back(v);
                e2[v].push_back(u);
                e1[v].push_back(v);
                e2[u].push_back(v);
            }
        }
        dj1();
        dj2();
        int ans = 0;
        for (int i = 1; i <= n; i++)
        {
            if (vis1[i] && vis2[i])
                ans = max(ans, dist2[i] - dist1[i]);
        }
        printf("%d", ans);
        return 0;
    }
    

    7.4804: 树网的核

    NOIP2007提高组T4
    在直径上尺取,计算每条路径的偏心距
    1、 通过Floyd算法求出顶点对之间的最短路径,并记录下具体的最短路径。
    2、 标记所有在直径上的点。
    3、 枚举路径的起点,进行DFS穷举路径的终点。
    4、 对于一条确定下来的路径,通过直接模拟的方法得出偏心矩。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=305;
    int G[maxn][maxn];
    int main()
    {
        int n,s;
        scanf("%d%d",&n,&s);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(i==j)G[i][j]=0;
                else G[i][j]=0x3f3f3f3f;
        for(int i=1,u,v,w;i<n;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            G[u][v]=G[v][u]=min(G[u][v],w);
        }
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
        int ans=1e9;
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j++)
            {
                if(G[i][j]>s)continue;
                int maxx=0;
                for(int k=1;k<=n;k++)
                    maxx=max(maxx,(G[i][k]+G[j][k]-G[i][j])/2);
                ans=min(ans,maxx);
            }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Servlet过滤器----Filter
    Servlet监听器详解及举例
    Servlet学习笔记(四)之请求转发与重定向(RequestDispatcher与sendRedirect)
    Servlet学习笔记(二)之Servlet路径映射配置、Servlet接口、ServletConfig、ServletContext
    Servlet学习笔记(三)之HttpServletResponse
    Servlet学习笔记(三)之HttpServletRequest
    Servlet学习笔记(一)之Servlet原理、初始化、生命周期、结构体系
    Python文件(File)及读写操作及生成器yield
    Python学习笔记摘要(一)类型 字符串 函数 列表 深浅拷贝
    Vue如何新建一个项目
  • 原文地址:https://www.cnblogs.com/BobHuang/p/13830053.html
Copyright © 2011-2022 走看看