zoukankan      html  css  js  c++  java
  • CSP-S day3

    今天又是爆零的一天(大雾)

    T1

    序列

    【题目背景】

    参加完 IOI2020 之后就是姚班面试。而你,由于讨厌物理、并且想成为乔布斯一样的创业家,被成功踢回贵系。转眼,时间的指针被指向 2023,大二, 12 月初,考试周。你早听学长说, 离散数学期中考很难,对竞赛生不友好,集训队选手做不完卷子。

    你冷笑。哼,堂堂国际金,这点难度的考试算什么。

    两小时,你看完习题解析前五章所有内容,并且倒背如流;

    一小时,你看了 500 页的讲义,并且记忆犹新;

    十分钟,你骑车到考场,自信的你只带了一把水笔,虽然考试让带资料;

    现在,摊开传说中神级卷子,你定神一看——

    【题目描述】

    你有一个递推式为An = ( ∑ j,n-1  Aj × j )% n,其中A1 = 1
    现在给出 n,你需要求出An
    的值

    【输入描述】

    一行,一个正整数 n
    【输出描述】

    一行,一个整数,表示An
    【样例输入 1

    2
    【样例输出 1

    1
    【数据范围】

    此题共 10 个测试点。
    对于前 10%的数据, n<=1
    对于前 40%的数据, n ≤ 10
    对于前 60%的数据, n ≤ 5000
    对于 100%的数据, 1 ≤ n ≤ 105
    【后记】

    “奋战两小时,考个四五十” 的表情包占领了你的朋友圈:

    • “啊,感觉自己人生完全了”

    • “但愿. . . . . .我真的能拿到四五十”

    • “我考完了. . . . . .考完了. . . . . .完了”

    • “曾经以为是开玩笑的,原来我还是 naïve 了”

    你冷笑。提前半小时交卷,你自然觉得, 离散数学,满分,正常

    这题我爆了!!!!爆了!!!!

    打了1e5的表,表炸了

    事实告诉我们

     防表防爆防骗=毒瘤题
    我的1e5的表啊
     
    然鹅这题的思路其实很简单
    因为手膜我们可以得到
    a[i]*i并不大,用long long就可以存下,然后再进行求值,时间复杂度是O(n)
     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 
     5 int n;
     6 int read()
     7 {
     8     int f=0,num;char ch;
     9     while(ch=getchar(),!isdigit(ch)) if(ch=='-') f=1;num=ch-'0';
    10     while(ch=getchar(), isdigit(ch)) num=num*10+ch-'0';
    11     return f?-num:num;
    12 }
    13 int main()
    14 {
    15     freopen("seq.in","r",stdin);
    16     freopen("seq.out","w",stdout);
    17     n=read();
    18     ll ans=1,a=1;
    19     for(int i=2;i<=n;i++)
    20     {
    21         a=ans%i;
    22         ans=ans+a*i;
    23     }
    24     printf("%lld",a);
    25     fclose(stdin);
    26     fclose(stdout);
    27     return 0;
    28 }

    T2

    片段划分


    【题目背景】

    研表究明,汉的字序顺并不定一能影阅响读。科学家们对数列进行了类似的研究。

    【题目描述】

      给一个正整数数列,若数列首项为数列中所有数的最小值,末项为数列中的最大值,则我们称这是个正确的数列。例如,序列[1,3,2,4][1,2,1,2]是正确的,但序列[1,3,2]不是。给出长度为 n 的序列[ 1 ,, n]。对于该序列的某个片段[ , 1 ,若该片段的首项为该片段中的最小值,末项为该片段中的最大值,则我们称这是个正确的片段。对于给定的序列,请求出该序列至少需要被分成多少段,才能使得每个片段均为正确的片段。序列[2,3,1,1,5,1]可以分为三个正确的段:[2,3][1,1,5][1]。需要编写一个程序,该程序按给定的顺序确定可以划分的最小正确段数。

    【输入格式】

      第一行一个正整数 n 表示序列长度接下来一行 n 个正整数 1 ,表示序列

    【输出格式】

      一个整数表示按照给定顺序可以划分的最小正确段数。

    【样例输入】

     5

      5 4 3 2 1

    【样例输出】

      5

    数据范围】

      本题共 3 Subtask
      对于 100%的数据,保证1 ≤ n ≤ 3 × 1e5,1 ≤a[i] ≤ 1e9
      Subtask1(30pts)n ≤ 500
      Subtask2(30pts)n ≤ 5000
      Subtask3(40pts):无特殊性质

     

    看到这道题就感觉是一道区间DP,最近也有在练来着,然鹅依然不会写,只好写了个O(n^3)的大大大暴力,30分滚粗

    正解是:对于任意一段子区间,最大数一定在末端,最小数一定在开头,快速找到这两个数的位置 分类分治

    如果最小值在最大值左边,那么最小值和最大值的区间一定是被划分的,如果刚好在所在大区间的两个端点,则这个区间就划分为一段

    若最小值或者最大值左边还有数,则划分为2个,对剩下的区间进行上述操作[l,最小值-1][最小值, 最大值]或者 [最小值,最大值][最大值+1,r]

    若最大值和最小值两侧还有数则划分为3个 [l,最小值-1][最小值,最大值][最大值+1,r]

    若最小值在最大值右边,则[l-最大值],[最大值+1,最小值-1],[最小值,r]

    这样时间复杂度是O(nlogn)

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        int f=0,num;char ch;
        while(ch=getchar(),!isdigit(ch)) if(ch=='-') f=1;num=ch-'0';
        while(ch=getchar(), isdigit(ch)) num=num*10+ch-'0';
        return f?-num:num;
    }
    const int N=3e5+5,K=21;
    int n,a[N],ans;
    int p[N]={-1},f1[N][K],f2[N][K],nxt[N][K];
    int getmin(int pre,int suf){return a[suf]<a[pre]?suf:pre;}
    int getmax(int pre,int suf){return a[pre]>a[suf]?pre:suf;}
    int Q1(int l,int r){int k=p[r-l+1];return getmin(f1[l][k],f1[r-(1<<k)+1][k]);}
    int Q2(int l,int r){int k=p[r-l+1];return getmax(f2[l][k],f2[r-(1<<k)+1][k]);}
    void dfs(int l,int r)//分治,找最大值和最小值
    {
        if(l>r) return;
        int minn=Q1(l,r),maxn=Q2(l,r);
        if(minn<=maxn)
            ++ans,dfs(l,minn-1),dfs(maxn+1,r);
        else
            dfs(l,maxn),dfs(maxn+1,minn-1),dfs(minn,r);
    }
    int main()
    {
        freopen("split.in","r",stdin);
        freopen("split.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++)
            p[i]=p[i>>1]+1,a[i]=read();
        for(int i=1;i<=n;i++)
            f1[i][0]=i,f2[i][0]=i,nxt[i][0]=i;
        for(int k=1;nxt[n+1][k-1]=n,k<p[n]+1;k++)
            for(int i=1;i<=n;i++)
                f1[i][k]=getmin(f1[i][k-1],f1[nxt[i][k-1]+1][k-1]),
                f2[i][k]=getmax(f2[i][k-1],f2[nxt[i][k-1]+1][k-1]),
                nxt[i][k]=nxt[nxt[i][k-1]+1][k-1];
        dfs(1,n);
        printf("%d",ans);
        fclose(stdin);fclose(stdout);
        return 0;
    }

    T3

    买一送一

    【题目描述】

    n 件物品,每件物品有一个价格。
    当你购买了一个价格为 x 的物品之后,可以选择一个价格严格小
    x 的物品,并把它免费拿走(也可以不拿)。
    现在,你要把这 n 个物品都买下来,问最少花费多少钱。
    【输入格式】
    第一行一个正整数 n,表示物品数量。
    接下来一行, n 个正整数,表示第 i 个物品的价格 a_i
    【输出格式】
    输出把 n 个物品都买下来最少的花费。
    【样例输入 1
    6
    3 4 5 3 4 5
    【样例输出 1
    14
    【样例解释 1
    买下价格为 4,5,5 的物品,并拿走 3,3,4 的物品,总共花费 14 元,
    可以证明这样是最少的。
    【样例输入 2
    5
    5 5 5 5 5
    【样例输出 2
    25
    【数据范围】
    本题共 7 个测试包
    对于所有数据, 1 ≤ n ≤ 200000 1 ≤ ≤ 10
    详细子任务附加限制及分值如下

    测试包编号 附加条件 分值
    1 n ≤ 20 25
    2 n ≤ 300 15
    3 n ≤ 5000 25
    4 = j (1 ≤ i < j ≤ n) 5
    5 j (1 ≤ i < j ≤ n) 5
    6 n≤50000, ≤3 10
    7 n ≤ 200000 15

    这是一道贪心!!!!

    但是我不会QAQ

    大佬的solution如下

    算法1
    考虑枚举哪些物品购买,剩下的贪心去选,判断是否能够全部选完。
    时间复杂度O(2^n*n) ,期望得分25

    算法2

    对于a[i]全部相同的,我们只能全部购买。
    对于a[i]全部不同的,我们显然是买最第 大的,取第 大的物品。
    时间复杂度 ,期望得分10分,结合算法1可以获得35分。

    算法3

    考虑把所有物品从大到小排序,对于价格相同的物品一起处理。假设当前处理到价格X ,价格为x的物品有a[x]个,令f[i]表示把所有价格大于x的物品都买(或者免费拿)完,现在还剩下 i个物品可以免费拿,最小的花费是多少。

    考虑枚举当前价格的物品买了多少个,剩下的都是免费选的。
    我枚举一个i,表示已经有i个可以免费拿这个物品要选,再枚举一个j表示这里我要购买j个物品,那
    么在满足i>=a[x]-j的情况下, 可以转移到 f[i-(a[x]-j)+j]

    时间复杂度O(n^2),期望得分65分,结合算法2可以获得75分

    算法4

    考虑a[i]<=3怎么做

    然鹅这题不会写

    原题来自CF

    http://codeforces.com/contest/335/problem/F

     

     总的来说这次模拟赛难度不大,应该要拿到100+60+15+

    然鹅我炸裂了!

    打表有风险


     

  • 相关阅读:
    Python Revisited Day 13 (正则表达式)
    Python Revisited Day 06 (面向对象程序设计)
    Python Revisited (变量)
    Python Revisited Day 05(模块)
    Python Revisited Day 04 (控制结构与函数)
    Python Revisited Day 03 (组合数据类型)
    Numpy
    Python Revisited Day 01
    Python3使用openpyxl读写Excel文件
    Python3操作YAML文件
  • 原文地址:https://www.cnblogs.com/Shayndel/p/11835442.html
Copyright © 2011-2022 走看看