zoukankan      html  css  js  c++  java
  • LibreOJ β Round #2

    这套题目真的不错,难度区分还是挺好的,后面的题目恕我愚笨,搞不定。

    先看看前面几个吧~~~

    A. 模拟只会猜题意

    内存限制:256 MiB 时间限制:1000 ms 标准输入输出
    题目类型:传统 评测方式:文本比较
     

    题目描述

    给定一个长度为 nnn 的序列 AAA 。

    定义 f(l,r)=∑i=lrAif(l,r)=sum_{i=l}^{r} A_{i}f(l,r)=i=lr​​Ai​​。

    询问 mmm 次,每次询问一个数字 xxx,请求出所有满足 r−l+1≥xr-l+1 ge xrl+1x 区间 [l,r][l,r][l,r] 中最大的 f(l,r)f(l,r)f(l,r)。

    输入格式

    第一行两个数,表示 nnn 和 mmm 。
    之后 nnn 个数,表示序列 AAA。
    之后 mmm 行每行一个数 xxx,表示询问 xxx 。

    输出格式

    输出 mmm 行,每行一个答案,表示最大的 f(l,r)f(l,r)f(l,r) 。

    样例

    样例输入

    5 5
    1 2 3 4 5
    1
    2
    3
    4
    5

    样例输出

    15
    15
    15
    15
    15

    数据范围与提示

    枚举起点和终点,刷新区间的最优值,就是长度为x的最优值,然后dp推一下,就是>=x的最优质。

    做到了O(1)的询问。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 1e4+5;
    int sum[maxn];
    int ans[maxn];
    int a[maxn];
    
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        memset(ans,-0x3f3f3f3f,sizeof(ans));
        for(int i = 1; i<=n; i++) scanf("%d",&a[i]);
    
        for(int i = 1; i<=n; i++) sum[i] = sum[i-1] + a[i];
    
        for(int i = 1; i<=n; i++) {
            for(int j = 0; j<i; j++) {
                ans[i-j] = max(ans[i-j],sum[i]-sum[j]);
            }
        }
    
        for(int i = n-1; i >=1 ; i--)
            ans[i] = max(ans[i],ans[i+1]);
    
        for(int i = 0; i < m; i++) {
            int x;
            scanf("%d",&x);
            printf("%d
    ",ans[x]);
        }
    
        return 0;
    }

    B. 贪心只能过样例

    内存限制:256 MiB 时间限制:1000 ms 标准输入输出
    题目类型:传统 评测方式:文本比较
     

    题目描述

    一共有 nnn个数,第 iii 个数 xix_ixi​​ 可以取 [ai,bi][a_i , b_i][ai​​,bi​​] 中任意值。
    S=∑xi2S = sum{{x_i}^2}S=xi​​2​​,求 SSS 种类数。

    输入格式

    第一行一个数 nnn。
    然后 nnn 行,每行两个数表示 ai,bia_i,b_iai​​,bi​​。

    输出格式

    输出一行一个数表示答案。

    样例

    样例输入

    5
    1 2
    2 3
    3 4
    4 5
    5 6

    样例输出

    26

    数据范围与提示

    1≤n,ai,bi≤1001 le n , a_i , b_i le 1001n,ai​​,bi​​100

    分析:

    可以考虑像多重背包一样,最后枚举和。

    有一个优化的方案,bitset,想法很奇妙,不停的右移前一步的结果,如果出现相同的,只会产生移动到同一位置。然后数1的个数。

    学一下bitset的使用。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 1e6+10;
    
    bitset<maxn> ans[105];
    
    int main()
    {
        int n;
        scanf("%d",&n);
    
        ans[0] = 1;
        for(int i = 1; i <= n; i++) {
            int l,r;
            scanf("%d%d",&l,&r);
            for(int j = l; j <= r; j++)
                ans[i] = ans[i] | ans[i-1]<<(j*j);
        }
    
        int cnt = 0;
        for(int i = 0; i <=1e6; i++)
            if(ans[n][i]==1) cnt++;
        printf("%d
    ",cnt);
    
        return 0;
    }

    bitset使用:

    一,定义和初始化
    
     bitset<n> b;                           //b有n位,每位都为0;
    
     bitset<n> b(u);                       //b是unsigned long型u的副本
    
     bitset<n> b(s);                       //b是string对象s中含有n位字符串的副本
    
     bitset<n> b(s, pos, n);             //b是s中从pos位置开始的n个位置的副本
    
     bitset<n> b(s,pos);                 //b从s的pos位置开始取值到s末尾(注取的值从b的右端开始)
    
     注:①n定义的位数在初始化时按初始值填充,赋值超出的范围舍去,空余的以零填充.
    
             ②bitset从string对象读入位集时按从右到左的顺序.
    
    二,操作
    
     b.any();                                 //查找b是否存在1?
    
     b.none();                               //b中不存在1吗?
    
     b.count();                              //b中1的个数
    
     b.size();                                //b的位数
    
     b[pos];                                 //访问b中pos处的数值
    
     b.test(pos);                          //检测b中pos处是否为1
    
     b.set();                                //把b中所有位 置为1
    
     b.set(pos);                           //把b中pos位置为1
    
     b.reset();                             //把b中所有位置为0
    
     b.reset(pos);                         //把b中pos位置为0
    
     b.flip();                                //b中所有二进制位取反
    
     b.flip(pos);                           //b中在pos处的二进制位取反
    
     b.to_ulong;                           //返回一个同值得unsigned long值
    
     os << b;                              //把b中位集输出

    C. DP 一般看规律

    内存限制:512 MiB 时间限制:1000 ms 标准输入输出
    题目类型:传统 评测方式:文本比较
     

    题目描述

    给定一个长度为 nnn 的序列 aaa,一共有 mmm 个操作。
    每次操作的内容为:给定 x,yx,yx,y,序列中所有 xxx 会变成 yyy。

    同时我们有一份代码:

    int ans = 2147483647;
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            if (a[i] == a[j])
                ans = std::min(ans, j - i);
        }
    }
    std::cout << ans << std::endl;
    

    请在每次修改后输出代码运行的结果。

    输入格式

    第一行两个数,表示 n,mn,mn,m。
    第二行 nnn 个数,表示 a1,a2,⋯,ana_1,a_2,cdots, a_na1​​,a2​​,,an​​。
    然后 mmm 行每行两个数 xxx 和 yyy,表示序列中所有 xxx 会变成 yyy。

    输出格式

    对于每次修改,输出答案。

    样例

    样例输入

    5 10
    2 7 6 3 8 
    6 1
    7 1
    1 3
    5 6
    1 7
    9 5
    1 10
    7 6
    7 5
    3 9

    样例输出

    2147483647
    1
    1
    1
    1
    1
    1
    1
    1
    1

    数据范围与提示

    1≤n,m≤1000001le n , m le 1000001n,m100000

    每个出现的数字绝对值在 int 范围内。

    竟然让我想到做法了,就是值:位置。

    全部把某一个数变成某一个数,就是合并区间。

    刚开始map<int,vector<int> > mp;但是时间复杂度到爆炸。大佬们是map<int,set<int> > mp;

    可以发现合并后答案只会减小,插入一个数,只可能影响到前后两个数。合并的时候是启发式合并。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int n,m;
    
    map<int,set<int> > mp;
    int ans = 2147483647;
    
    void insert(int v,int p) {
        auto it = mp[v].lower_bound(p);
        if(it!=mp[v].end()) ans = min(ans,*it-p);
        if(it!=mp[v].begin()) ans = min(ans,p-*--it);
        mp[v].insert(p);
    }
    
    
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        scanf("%d%d",&n,&m);
    
        int v;
        for(int i = 1; i<=n; i++) {
            scanf("%d",&v);
            insert(v,i);
        }
    
        int x,y;
        for(int z = 1; z<=m; z++) {
            scanf("%d%d",&x,&y);
            if(x==y) {
                printf("%d
    ",ans);
                continue;
            }
            if(mp[x].size()>mp[y].size()) swap(mp[x],mp[y]);
            for(auto it = mp[x].begin(); it!=mp[x].end(); ++it) {
                insert(y,*it);
            }
            mp[x].clear();
            printf("%d
    ",ans);
        }
    
        return 0;
    }
  • 相关阅读:
    【BZOJ5302】[HAOI2018]奇怪的背包(动态规划,容斥原理)
    【BZOJ5303】[HAOI2018]反色游戏(Tarjan,线性基)
    【BZOJ5304】[HAOI2018]字串覆盖(后缀数组,主席树,倍增)
    【BZOJ5305】[HAOI2018]苹果树(组合计数)
    【BZOJ5300】[CQOI2018]九连环 (高精度,FFT)
    【BZOJ5292】[BJOI2018]治疗之雨(高斯消元)
    【BZOJ5298】[CQOI2018]交错序列(动态规划,矩阵快速幂)
    【BZOJ5289】[HNOI2018]排列(贪心)
    Codeforces Round #539 Div1 题解
    【BZOJ5288】[HNOI2018]游戏(拓扑排序)
  • 原文地址:https://www.cnblogs.com/TreeDream/p/7763472.html
Copyright © 2011-2022 走看看