zoukankan      html  css  js  c++  java
  • 第十关——CCF线上赛 普及组

    14:30:35 背影是真的,人是假的,没什么执着。——王菲《百年孤寂》

    第一题 文具订购

    题目描述

    小明的班上共有 n 元班费,同学们准备使用班费集体购买 3 种物品:

    1. 圆规,每个 77 元。

    2. 笔,每支 44 元。

    3. 笔记本,每本 33 元。

    小明负责订购文具,设圆规,笔,笔记本的订购数量分别为 a,b,c,他订购的原则依次如下:

    1. n元钱必须正好用光,即 7a+4b+3c=n

    2. 在满足以上条件情况下,成套的数量尽可能大,即 a,b,c 中的最小值尽可能大。

    3. 在满足以上条件情况下,物品的总数尽可能大,即 a+b+c 尽可能大。

    请你帮助小明求出满足条件的最优方案。可以证明若存在方案,则最优方案唯一。

    输入格式

    输入仅一行一个整数,代表班费数量 n

    输出格式

    如果问题无解,请输出 -1

    否则输出一行三个用空格隔开的整数 a, b, c分别代表圆规、笔、笔记本的个数。

    输入输出样例

    输入 #1

    1

    输出 #1

    -1

    输入 #2

    14

    输出 #2

    1 1 1

    输入 #3

    33

    输出 #3

    1 2 6

    说明/提示

    样例输入输出 3 解释

    a=2,b=4,c=1也是满足条件 1,2的方案,但对于条件 3,该方案只买了 7个物品,不如 a=1,b=2,c=6的方案。

    数据规模与约定

    • 对于测试点 16,保证 n leq 14n14。

    • 对于测试点 712,保证 n 是 14的倍数。

    • 对于测试点 1318,保证 n100。

    • 对于全部的测试点,保证 0n100000

    这道题可以用暴力枚举, 由7a+4b+3c=n可知,a是abc中最小的一个数,一定小于n/14,于是这就是第一个循环,第二个循环与第三个循环的条件上限我是选的最小的一个写,然后就是一个简单的if语句输出后就直接return,防止有两组情况,因为 a,b,c 中的最小值尽可能大,所以第一个循环是从大到小--。

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        int n;
        scanf("%d",&n);
        if(n==0)
        {
            printf("0 0 0");
            return 0;
        }
        for(int i=n/14;i>=0;i--)
        for(int j=i;j<=n/3;j++)
        for(int k=i;k<=n/3;k++)
        {
            if(7*i+4*j+3*k==n)
            {
                printf("%d %d %d",i,j,k);
                return 0;
            }
        }
        printf("-1");
        return 0;
    }

    第二题 跑步

    题目描述

    小 H 是一个热爱运动的孩子,某天他想给自己制定一个跑步计划。小 H 计划跑 nn 米,其中第 i(i geq 1)i(i1)分钟要跑 x_ixi 米(x_ixi 是正整数),但没有确定好总时长。

    由于随着跑步时间增加,小 H 会越来越累,所以小 H 的计划必须满足对于任意 i(i >1)i(i>1) 都满足 x_i leq x_{i-1}xixi1

    现在小 H 想知道一共有多少个不同的满足条件的计划,请你帮助他。两个计划不同当且仅当跑步的总时长不同,或者存在一个 ii,使得两个计划中 x_ixi 不相同。

    由于最后的答案可能很大,你只需要求出答案对 pp 取模的结果。

    输入格式

    输入只有一行两个整数,代表总米数 nn 和模数 pp。

    输出格式

    输出一行一个整数,代表答案对 pp 取模的结果。

    输入输出样例

    输入 #1

    4 44

    输出 #1

    5

    输入 #2

    66 666666

    输出 #2

    323522

    输入 #3

    66666 66666666

    输出 #3

    45183149

    说明/提示

    样例输入输出 1 解释

    五个不同的计划分别是:{1,1,1,1},{2,1,1},{3,1},{2,2},{4}。


    数据规模与约定

    本题共 1010 个测试点,各测试点信息如下表。

    测试点编号

    n

    测试点编号

    n

    11

    55

    66

    2 imes 10^32×103

    22

    1010

    77

    5 imes 10^35×103

    33

    5050

    88

    2 imes 10^42×104

    44

    100100

    99

    5 imes 10^45×104

    55

    500500

    1010

    10^5105

    对于全部的测试点,保证1n10^5,1p<2^30。

    70分代码就是找规律然后递推???但是我听他们说这叫DP???,不管了,放代码

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    ll f[100001];
    int n,p;
    int main()
    {
        scanf("%d%d",&n,&p);
        f[0]=1;
        for(int i=1;i<=n;++i)
        for(int j=i;j<=n;++j)
        f[j]=f[j]%p+f[j-i]%p;
        printf("%d",f[n]);
        return 0;
    }

    真的是短到我无话可说!

    100分代码是标准dp,是一个二维dp,思路差不多吧,注意最后要清空o的值。(经常忘然后就会检查好久好久!!!)

    #include<bits/stdc++.h>
    #define ll long long 
    using namespace std; 
    ll d[100001],f[1001][100001];
    int main()
    {
        int n,p;
        scanf("%d%d",&n,&p);
        int m=sqrt(n)+1;
        d[0]=f[0][0]=1;
        for(int i=1;i<m;i++)
        {
            for(int j=i;j<=n;j++)
            {
                d[j]=(d[j]+d[j-i])%p;
            }
        }
        for(int i=1;i<m;i++)
        {
            for(int j=i;j<=n;j++)
            {
                f[i][j]=f[i][j-i];
                if(j>=m) f[i][j]=(f[i][j]+f[i-1][j-m])%p;
            }
        }
        ll ans=0,o=0;
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<m;j++)
            {
                o=(o+f[j][n-i])%p;
            }
            ans+=o*d[i];
            ans%=p;
            o=0;
        }
        printf("%d",ans);
        return 0;
    }

    第三题  魔法

    题目描述

    C 国由 n 座城市与 m 条有向道路组成,城市与道路都从 1 开始编号,经过 i 号道路需要 ti 的费用。

    现在你要从 1 号城市出发去 n 号城市,你可以施展最多 k 次魔法,使得通过下一条道路时,需要的费用变为原来的相反数,即费用从 ti 变为ti。请你算一算,你至少要花费多少费用才能完成这次旅程。

    注意:使用魔法只是改变一次的花费,而不改变一条道路自身的 ti;最终的费用可以为负,并且一个城市可以经过多次(包括 n 号城市)。

    输入格式

    输入的第一行有三个整数,分别代表城市数 n,道路数 m 和魔法次数限制 k。

    第 2 到第(m+1) 行,每行三个整数。第 (i+1) 行的整数 ui,vi,ti 表示存在一条从 ui 到 vi 的单向道路,经过它需要花费ti

    输出格式

    输出一行一个整数表示最小的花费。

    输入输出样例

    输入 #1

    4 3 2

    1 2 5

    2 3 4

    3 4 1

    输出 #1

    -8

    输入 #2

    2 2 2

    1 2 10

    2 1 1

    输出 #2

    -19

    说明/提示

    输入输出样例 1 解释

    依次经过 1 号道路、2 号道路、3 号道路,并在经过 1,2 号道路前使用魔法。

    输入输出样例 2 解释

    依次经过 1 号道路、2号道路、1 号道路,并在两次经过 1号道路前都使用魔法。

    SPFA80分代码,改了很久,思路不是特别清楚,但是还是超时(注意变量赋值一定要大!!!很大很大的那种)

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    typedef pair <int,int> P;
    int n,m,k,h[102],vis[102][200004];
    ll d[102][200004];
    queue <P> q;
    struct sby{
        int to,nt,len;
    } e[1000003];
    void spfa() {
        for(int i=1; i<=n; i++) 
        for(int j=0; j<=k; j++) 
        d[i][j]=999999999;
        d[1][0]=0;
        q.push(P(1,0));
        vis[1][0]=1;
        while(!q.empty()) 
        {
            int a=q.front().first;
            int x=q.front().second;
            q.pop();
            vis[a][x]=0;
            for(int i=h[a];i;i=e[i].nt) 
            {
                int y=e[i].to,z=e[i].len;
                if(d[y][x]>d[a][x]+z) 
                {
                    d[y][x]=d[a][x]+z;
                    if(!vis[y][x]) 
                    {
                        q.push(P(y,x));
                        vis[y][x]=1;
                    }
                }
                if(x<k && d[y][x+1]>d[a][x]-z) 
                {
                    d[y][x+1]=d[a][x]-z;
                    if(!vis[y][x+1]) 
                    {
                        q.push(P(y,x+1));
                        vis[y][x+1]=1;
                    }
                }
            }
        }
    }
    int main() {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1; i<=m; i++) {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            e[i].to=y;
            e[i].nt=h[x];
            e[i].len=z;
            h[x]=i;
        }
        spfa();
        ll ans=999999999;
        for(int i=0; i<=k; i++) 
        ans=min(ans,d[n][i]);
        printf("%lld
    ",ans);
        return 0;
    }

    正在想办法可不可以利用一些手段省一些时间复杂度,不用把整篇代码都改了

  • 相关阅读:
    转:基于科大讯飞语音API语音识别开发详解
    转:Netty系列之Netty高性能之道
    转:hadoop知识整理
    转:nginx防DDOS攻击的简单配置
    转:Google论文之一----Bigtable学习翻译
    POJ 2112 Optimal Milking(最大流+二分)
    HDU 4647 Another Graph Game(贪心)
    HDU 4671 Partition(定理题)
    HDU 4648 Magic Pen 6
    HDU 4649 Professor Tian(DP)
  • 原文地址:https://www.cnblogs.com/wybxz/p/12494256.html
Copyright © 2011-2022 走看看