• NEERC2014训练日志


    solved 4 (A B J K)

    rank 144/237

    卡题,卡题,卡题,每题都卡!!!好几个题,都是因为小细节上写错,导致卡了很久的。

    多训练,多打比赛,总结新题和陈题之间的异同,把一些不良的编码习惯给磨掉,竞赛水平可提升很多。

    https://vjudge.net/contest/220476

    A - Alter Board (通过)

    <qj>

    一开始选择了错误的贪心思想,后面尝试画出3*3矩阵的时候找到了正确思路:

    由于一开始的矩阵是全都错开的:

    # @ #

    @#@

    # @ #

    我们把第二列翻转可得到

    #  #  #

    @@@

    #  #  #

    结果就很明显了。(以后一道题找不到代码bug就要考虑思路bug,换人重新读题做一遍比较好。)

    B-Burrito King (通过)

    <qj>

    题意:在满足A的开心度的同时,要照顾B的不开心度,贪心求A的最大开心度。

    思路:

    由于可取浮点数,那么每类物品的A开心度和B不开心度的比值就是我们贪心的方向。

    按比例由大到小排序便可,这样保证最优。

    求解时,推一个式子便可。

    注意数据范围!!!有很多个数据都包括了0

    F-Filter

     一、题意

      给一个数字$m$,表示后面说的数据文件包含的记录的二进制位数;一个$f$,表示后面有$f$个哈希函数,接下来$f$个数字$a_i(0 \le i < f)$,表示哈希函数的参数;接下来给一个数字$n$,表示后面有$n$个数据文件;接下来给$n$行字符串,代表数据文件中记录的十六进制($0123456789abcdef$)表示(注意:这是题目的关键点。数据文件的十六进制表示,对应的二进制,是按字符大端存储的。即:比如第一个字符是$e$,二进制表示为$1110$,那么,该数据文件中记录的第$0-3$位分别是:$0$、$1$、$1$、$1$。按字符大端存储的意思就是说:一个字符二进制表示的高位(在这儿右边的是高位,因为是字符串嘛),对应实际数据文件记录的低位。可能没讲清楚。通俗化表示就是:拿样例说话,$m=23$,第一个数据文件的记录为$effde7$,对应的二进制表示为$1110\ 1111\ 1111\ 1101\ 1110\ 0111$,那么,数据记录的第$0-22$位分别为:0-1-1-1 1-1-1-1 1-1-1-1 1-0-1-1 0-1-1-1 1-1-1。另外,题目中强调了最后一个字符的存储模式。讲的很绕,硬是猜出来的意思。然而,比赛过程中,就是被这个地方给坑了。其实最后一个字符的存储模式和前面的没任何区别,只是要少数$4-m\%4$个二进制位而已)。然后接下来一个$q$,表示用户的个数。接下$q$个数字,表示$q$个用户的id。

      题目要计算的是,有多少个数据文件的记录包含至少一个用户。一个数据文件记录包含一个用户的含义是:假设数据文件记录为$R$,用户的id为$u$,如果对于所有哈希函数的参数$a_i(0 \le i < f)$,通过哈希函数$j = (u * a_i)\ \% m$得到的所有$j$,记录$R$的第$j$位都是$1$,就说明这个数据文件记录包含这个用户。

    二、思路

      搞懂题意后,预处理出每一个用户的所有$j$,放到bitset里面(不是必须,数组也可以。只是后面比较起来复杂度会大一点而已。),假设是$b$;然后枚举每一个数据文件记录$R$,再枚举每一个用户的$b$,如果$R\ \&\ b\ ==\ b$,说明记录$b$的每一个是$1$的二进制位在$R$中都是$1$,那么,这个数据文件是满足题目要求的。

      注意范围,$a_i$和$u_k$都是$[1, 2^{31})$,别相乘后溢出了。

    三、源代码

    #include <bits/stdc++.h>
    using namespace std;
    #define MAXN 1024
    typedef long long LL;
    int m, f, n, q, a[MAXN];
    char str[MAXN][MAXN / 4 + 10];
    bitset<MAXN> df[MAXN], uh[MAXN];
    vector<int> ans;
    int main() {
        while(~scanf("%d%d", &m, &f)) {
            for(int i = 0; i < MAXN; ++i)df[i].reset();
            for(int i = 0; i < MAXN; ++i)uh[i].reset();
            ans.clear();
            for(int i = 0; i < f; ++i)scanf("%d", a + i);
            scanf("%d", &n);
            for(int i = 0; i < n; ++i) {
                scanf("%s", str[i]);
                int len = strlen(str[i]);
                for(int j = 0; j < len; ++j) {
                    int t = isdigit(str[i][j]) ? str[i][j] - '0' : str[i][j] - 'a' + 10;
                    if(j == len - 1 && m % 4 != 0) {
                        if(m % 4 == 1) {
                            if(t & (1 << 0))df[i].set(j * 4 + 0);
                        }
                        if(m % 4 == 2) {
                            if(t & (1 << 0))df[i].set(j * 4 + 0);
                            if(t & (1 << 1))df[i].set(j * 4 + 1);
                        }
                        else if(m % 4 == 3) {
                            if(t & (1 << 0))df[i].set(j * 4 + 0);
                            if(t & (1 << 1))df[i].set(j * 4 + 1);
                            if(t & (1 << 2))df[i].set(j * 4 + 2);
                        }
                    }
                    else {
                        if(t & (1 << 0))df[i].set(j * 4 + 0);
                        if(t & (1 << 1))df[i].set(j * 4 + 1);
                        if(t & (1 << 2))df[i].set(j * 4 + 2);
                        if(t & (1 << 3))df[i].set(j * 4 + 3);
                    }
    
                }
                //cout << df[i] << endl;
            }
            scanf("%d", &q);
            LL u;
            for(int i = 0; i < q; ++i) {
                cin >> u;
                for(int j = 0; j < f; ++j) {
                    uh[i].set((u * a[j]) % m);
                }
            }
            for(int i = 0; i < n; ++i) {
                for(int j = 0; j < q; ++j) {
                    if((df[i]&uh[j]) == uh[j]) {
                        ans.push_back(i);
                        break;
                    }
                }
            }
            if(ans.size() == 0)printf("%d\n", ans.size());
            else printf("%d ", ans.size());
            for(int i = 0; i < ans.size(); ++i)printf("%d%c", ans[i], i == int(ans.size()) - 1 ? '\n' : ' ');
        }
        return 0;
    }

    I-Improvements

    J-Jokewithpermutation (通过)

    一、思路

      <错误的做法>

      统计每一个数字在字符串中的出现次数。那么,必定存在至少一个数字的出现次数是1。把这些出现次数是1的数字都push到队列中。然后,用类似于bfs的方式处理:取出队列的头元素e,找出它在字符串中的出现位置(不预处理也可以,每次都搜索一遍),然后,它影响的数字最多有四个。比如,全排列字符串为$...1234...$,我们取出的队列头元素是$23$,那么,数字$12$、$2$、$3$、$34$的出现次数都减少了$1$。当然,如果取出的数字是$1$位数,那么,它只影响三位(写代码的时候被这个细节坑了好多发RE的)。如果被$e$影响的数字次数为$1$了(被影响的数字肯定出现次数大于$1$),把它放到优先队列里面。同时把元素$e$在字符串中的出现位置上替换成#字符。

      最后,当剩余的所有数字的出现次数都大于$1$时,我天真地得出这么个结论(错的):此时序列必定满足...###111···###...###222···###...这种形式。由公式$n\ =\ len\ >\ 9\ ?\ \frac{len-9}{2}\ +\ 9\ :\ len$可计算出$n$,从$n$到$1$枚举每一个没在队列中出现过的数字,

      <正确的做法>

      dfs暴力搜索即可。只要剪枝用的好,没有题目A不了。

    K-Knockout Racing (通过)

    <qj>

    思路:

    n*k也就1e6,直接暴力呀。

    计算时要注意a和b的关系,如果a在b的左边,是一种做法;

    如果a在b的右边,是另一种做法。

    设 l = abs(a-b)

    那么在t时间内,已经完整走过了time =  t/l 次,剩下rest = t%l ,这时候判断 t/l 的奇偶性,然后判断起始方向便可。

  • 相关阅读:
    Java并发编程 LockSupport源码分析
    [No000010F]Git8/9-使用GitHub
    [No000010E]Git7/9-标签管理
    [No000010D]Git6/9-分支管理
    [No000010C]Git5/9-远程仓库
    [No000010B]Git4/9-时光机穿梭
    [No000010A]Git3/9-创建版本库
    [No0000109]Git2/9-安装Git
    [No0000108]Git1/9-Git简介与入门
    [No000011D].NETCORE1/19-.NET Core 指南
  • 原文地址:https://www.cnblogs.com/dowhile0/p/8726861.html
Copyright © 2020-2023  润新知