zoukankan      html  css  js  c++  java
  • 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 的奇偶性,然后判断起始方向便可。

  • 相关阅读:
    leetcode 190 Reverse Bits
    vs2010 单文档MFC 通过加载位图文件作为客户区背景
    leetcode 198 House Robber
    记忆化搜索(DP+DFS) URAL 1183 Brackets Sequence
    逆序数2 HDOJ 1394 Minimum Inversion Number
    矩阵连乘积 ZOJ 1276 Optimal Array Multiplication Sequence
    递推DP URAL 1586 Threeprime Numbers
    递推DP URAL 1167 Bicolored Horses
    递推DP URAL 1017 Staircases
    01背包 URAL 1073 Square Country
  • 原文地址:https://www.cnblogs.com/dowhile0/p/8726861.html
Copyright © 2011-2022 走看看