zoukankan      html  css  js  c++  java
  • 8.1集训

    上午

    考试

    第一题

    一句话题意:给你几堆火,给你几个罐子,这几个罐子分别对火可能会产生不同的影响,每次使用罐子的时候都必须对全部的火进行操作,(1)表示浇灭,(0)表示
    无影响,(-1) 表示点燃

    问最少用几次罐子可以把火浇灭,否则输出“-1”

    一眼搜索

    #include <bits/stdc++.h>
    #define LL long long
    #define debug
    using namespace std;
    
    const int N = 1e3+250;
    
    queue<int>q;
    map<LL, int> vis, dis; 
    int n, m;
    int zuikaishideyangzi, moweideyangzi;
    int a[250][250];
    
    inline void shuruyijichushihua() {
       cin >> n >> m;
       for (int i = 1; i <= n; ++ i) zuikaishideyangzi = zuikaishideyangzi * 10 + 1;
       dis[zuikaishideyangzi] = 0;
       vis[zuikaishideyangzi] = 1;
       for (int i = 1; i <= m; ++ i) {
          for (int j = 1; j <= n; ++ j) {
             cin >> a[i][j];
          }
       }
       q.push(zuikaishideyangzi);
       return;
    }
    
    inline void jiejuewenti() {
       while (q.size()) {
          int now = q.front(); q.pop();
          if (now == moweideyangzi) return;
          int tmp = n, shu[66], yuan[66];
          int xianzaideyangzi = now;
          while (tmp != 0) {
             yuan[tmp] = shu[tmp] = xianzaideyangzi%10;
             -- tmp;
             xianzaideyangzi /= 10;
          }
          for (int i = 1; i <= m; ++ i) {
             for (int j = 1; j <= n; ++ j) {
                if (a[i][j] == 1) shu[j] = 0;
                   if (a[i][j] == -1) shu[j] = 1;
             }
             LL houlainayiwei = 0;
             for (int j = 1; j <= n; ++ j) {
             houlainayiwei = houlainayiwei*10 + shu[j];
             shu[j] = yuan[j];
             }
             if (!vis.count(houlainayiwei)) {
                vis[houlainayiwei] = 1;
                dis[houlainayiwei] = dis[now] + 1;
                q.push(houlainayiwei);
             }
          }
       }
    }
    
    inline void shuchudaan() {
       if (vis[moweideyangzi]) cout << dis[moweideyangzi];
       else puts ("-1");
       return;
    }
    
    inline int thestars() {
       shuruyijichushihua();
       jiejuewenti();
       shuchudaan();
       return 0;
    }
    
    int youngore = thestars();
    
    signed main() {;}
    

    第二题

    photo

    一眼贪心,我们观察样例以及样例解释

    Code
    3 1
    2 2
    4 3
    样例解释:
    如果没人躺过来,需要27的面积。
    我们只要让第1个人躺过来,就只需要21的面积!
    

    开始揣测,为什么一定要让第一个人的(w)(h)翻转?为什么不是别人?如果别人翻转会是什么样子的?

    画图发现

    在第一个人的(w)(h)翻转前后,他们的(maxh)一直都是3,只是他们的(sumw)变小了,所以整体的体积变小了

    在经过一段时间的臆想,我决定给他们按某种方式的排序,或许会好做一些

    考虑:按(h)的高度大小排序?显然不合适,没有考虑全体,缺点太多

    考虑:按(w)的大小排序?显然要被否定

    于是继续臆想,最终决定按一个数的(h)(w)的差值来从大到小来排序(他们的绝对值)

    于是原来的样例变成这样:

    Code
    3 1(3-1=2)
    4 3(4-3=1)
    2 2(2-2=0)
    

    我们肯定优先是对那些(h)(w)差值大的组合进行翻转,因为只有这样才有可能对答案产生有效或者更大的贡献

    这时候再来考虑:

    (h)(w)大小的关系

    • (w > h)
    • (w < h)
    • (w = h)

    显然对于第三种情况我们无论是否调换(w)(h)都是无影响的

    分情况讨论第一种与第二种情况:

    (w>h)的时候,考虑(w)是否影响(maxh)

    1.(w <maxh),此时交换(w)(h)显然是优的,因为我们在(maxh)没有变动的情况下,是的(sumw)尽量的小

    2.(w>maxh),这时候直接交换不一定是优的,因此我们需要计算一下交换之后的面积

    如果(面积_{当前算出来的} >面积_{以前算出来的}) 显然不优,我们不去交换(w)(h),反之则交换,并注意更新(maxh)与一些数组

    (w < h)的时候,考虑(maxh)(h)的关系

    1.(h eq maxh),显然,我交换之后不影响你(h)的最大值,并且交换之后,我(sumw)还变大了,面积也会变大,显然不优,我们不去交换

    2.(h = maxh),还要继续分析:

    整体序列是否只有这么一个(maxh),那我们需要计算交换之后的面积,然后……(上文提过,此处省略)

    如果不止一个(maxh),那我们交换之后显然吃亏,因为我们交换之后的(h)没有影响到(maxh)并且我的(sumw)也变大了

    算法整体就结束了,不过仍然有一个细节要注意,因为题目规定,要求不超过(dfrac n 2)的修改个数,所以每一次交换之后,都需要累加计数器,如果发现计数器大于(dfrac n 2)就退出
    底下是90分代码,还需要经过我再D一下

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <cmath>
    //#define debug
    using namespace std;
    
    const int N = 1e5+66;
    
    struct node {int h, w, cha;}a[N];
    
    inline int cmp(node x, node y) {return x.cha > y.cha;}
    
    int n, m, sum;
    int sumw[N], maxh = -N;
    
    int main () {
       scanf ("%d", &n);
       m = n>>1;
       int dodododo = 0;
       for (int i = 1; i <= n; ++ i) {
          scanf ("%d%d", &a[i].w, &a[i].h);
          a[i].cha = abs(a[i].w-a[i].h);
          dodododo += a[i].w;
          maxh = (maxh>a[i].h)?maxh:a[i].h;
       }
       sum = dodododo*maxh;
    #ifdef debug
    cout << "dodododo-->" << dodododo << ' ' << "maxh-->" << maxh << '
    ';
    cout << "sum-->" << sum << '
    '; 
    #endif 
       sort (a+1, a+n+1, cmp);
    #ifdef debug
    for (int i = 1; i <= n; ++ i) cout << a[i].w << ' ' << a[i].h << '
    ';
    #endif
       for (int i = 1; i <= n; ++ i) sumw[i] = sumw[i - 1] + a[i].w;
       for (int i = 1; i <= n; ++ i) {
          if (m == 0) break;
          if (a[i].w > a[i].h) {
             if (a[i].w <= maxh) {
                sum = maxh*(sumw[i - 1]+a[i].h+sumw[n]-sumw[i]);
                swap(a[i].w, a[i].h);
                for (int j = i; j <= n; ++ j) sumw[j] = sumw[j - 1] + a[j].w;
                -- m;
             } else {
                int ans = a[i].w*(sumw[i-1]+a[i].h+sumw[n]-sumw[i]);
                if (ans < sum) {
                   sum = ans;
                   for (int j = i; j <= n; ++ j) maxh = a[i].w;
                   -- m;
    	    } else continue;
    	 }
          }
          if (a[i].w == a[i].h) {continue;}
          if (a[i].w < a[i].h) {
             if (maxh != a[i].h) {continue;}
             if (maxh == a[i].h) {
                int flag = 0;
                for (int j = 1; j <= n; ++ j)
                   if (a[j].h == maxh) ++ flag;
                flag -= 1;
                if (flag) {continue;}
                else {
                   int one = -N;
    	       for (int j = 1; j < i; ++ j) one =(one>a[j].h)?one:a[j].h;
    	       for (int j = i+1; j <= n; ++ j) one =(one>a[j].h)?one:a[j].h;
    	       one = (one>a[i].w)?one:a[i].w;
    	       int ans = one*(sumw[i-1]+a[i].h+sumw[n]-sumw[i]);
    	       if (ans < sum) {
                      sum = ans;
                      maxh = one;
                      swap(a[i].w, a[i].h);
                      for (int j = i; j <= n; ++ j)sumw[j]=sumw[j - 1] + a[i].w;
                   } else {continue;}
                }
             }
          }
       }
       cout << sum;
       return 0;
    }
    

    第三题

    eat

    一眼枚举

    关于吃东西这道题,我们首先来分析一下题意

    给你(ABCD)四堆数,告诉每堆数里面你必须选一个,再给你一个判定器n,问你有多少种方案选数?

    最暴力的做法,四重for,可以拿到三十分

    然后考虑优化,最简单的优化是知道前三个数,然后利用判定器减去前三数的和就可以得到第四个数

    在这个题中,我们如果知道了(A+B)的和,就可以很容易的推出(C+D)的具体范围,

    具体做法:枚举出(A+B)的所有组合,再枚举(C+D)的所有组合,

    我们定义(C1,C2)数组

    其中(C1[i]=x)就表示(A+B)所能凑出来的和的第(i)种方案,其价值为(x),同理

    (C2[i] = x)表示(C+D)所能凑出来的和的第(i)种方案,其价值为(x)

    (C2)数组中找到能与(C1)数组匹配的数的下标,然后就可以累加答案

    更具体的分析在代码中

    下面是自己的代码:

    #include <bits/stdc++.h>
    #define int long long 
    #define LL long long
    #define debug
    using namespace std;
    
    const int N = 1e8+66, M = 5e3+66, P = 2e7+2;
    
    int n, cnt1, cnt2, maxn, res;
    int A, B, C, D;
    int a[M], b[M], c[M], d[M];
    int c1[P], c2[N], f[N];
    inline int thestars() {
       cin >> n >> A >> B >> C >> D;
       for (int i = 1; i <= A; ++ i) cin >> a[i];
       for (int i = 1; i <= B; ++ i) cin >> b[i];
       for (int i = 1; i <= C; ++ i) cin >> c[i];
       for (int i = 1; i <= D; ++ i) cin >> d[i];
       for (int i = 1; i <= A; ++ i) {
          for (int j = 1; j <= B; ++ j) {
             if (a[i] + b[j] <= n) {
                ++ f[a[i] + b[j]];
    	    maxn = max (maxn, a[i] + b[j]);
    	 }
          }
       }
       for (int i = 0; i <= maxn; ++ i) {
          while (f[i]) {
             -- f[i];
             c1[++ cnt1] = i;
          }
       }
       maxn = 0;
       for (int i = 1; i <= C; ++ i) {
          for (int j = 1; j <= D; ++ j) {
             if (c[i] + d[j] <= n) {
             ++ f[c[i] + d[j]];
             maxn = max (maxn, c[i] + d[j]);
             }
          }
       }
       for (int i = 0; i <= maxn; ++ i) {
          while (f[i]) {
             -- f[i];
             c2[++ cnt2] = i;
          }
       }
       int cur;
       for (cur = cnt2; cur >= 1; -- cur)
          if (c1[1] + c2[cur] <= n)
             break;
       //我们在C2数组中寻找最后一个能与C1[1]相匹配的数的下标
       //何为匹配?我加上你可以在判定器的范围之内
       //所以应该倒序枚举,保证前边的一定可以匹配
       for (int i = 1; i <= cnt1; ++ i) {
          res += cur;
    //cur表示的是在C2数组中最后一个能与当前的C1[i]匹配的下标
          while (cur && c1[i + 1] + c2[cur] > n)
             -- cur;
    //cur这个计数器需要不断往前更新,一直在找,能与C1数组中匹配的下标
       }
       cout << res << '
    ';
       return 0;
    }
    
    int youngore = thestars();
    
    signed main() {;}
    
  • 相关阅读:
    我叫mt3.0更新公告
    gcc 编译器常用的命令行参数一览
    C++两个类相互引用错误留影
    C++中的声明与定义
    C++ 杂记
    C++中两个类相互包含引用的相关问题
    Ogre 中使用OIS的两种模式
    Ogre 渲染队列(二)
    Ogre 渲染队列(一)
    Ogre 场景管理器
  • 原文地址:https://www.cnblogs.com/yszhyhm/p/13413939.html
Copyright © 2011-2022 走看看