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

    上午

    考试

    第一题

    给你一个初始序列,和两个操作:操作1可以使得(i)(i+2)两个数交换位置,操作2是相邻的数可以交换位置

    问:这个序列最少用多少次操作2可是使序列单调递增?

    你考虑,操作1的性质:使得(i)(i+2)两个数交换位置,不就是奇偶性相同的位置吗?而操作2的性质:相邻的数可以交换位置,不就是奇偶性不同的数吗?

    把原序列排序之后,对于为排序的序列,我们考虑当前这个数的下标与排完序之后的下标,如果发现他们奇偶性相同,也就是说,可以经过若干次操作1可以变换到那个位置

    如果发现奇偶性不同,说明肯定是经过了一次操作1,因此计数器叠加

    注意细节:这样统计是真实答案的二倍,因为:假如当前在(i),你发现这个数排完序之后在(j)(i < j)),且(i,j)的奇偶性不同,这时你计数器累加,但是到了(j)那个位置,你的计数器还会叠加,也就是说,你的计数器对于同一种情况增加了两次

    #include <bits/stdc++.h>
    #define LL long long
    #define debug
    using namespace std;
    
    const int N = 2e5+66;
    
    int n, res;
    int a[N], b[N];
    
    inline int thestars() {
       cin >> n;
       for (int i = 1; i <= n; ++ i) {
          cin >> a[i];
          b[i] = a[i];
       }
       sort(b+1, b+n+1);
       for (int i = 1; i <= n; ++ i) {
          int pos = lower_bound(b+1, b+n+1, a[i]) - b;
          if ((pos&1) != (i&1)) ++ res;
       }
       cout << (res/2);
       return 0;
    }
    
    int youngore = thestars();
    
    signed main() {;}
    

    第二题

    (10^8)条横向道路与竖向道理,相邻的道路之间相差(100m),从左到右第(i)条纵向街道和从下到上第(j)条横向街道之间的交点描述为((i,j)),在某些交点上建有以交点为圆心,半径是 (10) 米的喷泉,行走时不能穿过喷泉。

    问你要从((x_1,x_2))走到((x_2,y_2))最短要走多少?

    Sample Input
    1 1 6 5
    3
    3 2
    5 3
    2 4
    
    Sample Output
    891.415926535897938
    

    (10^8)条横向道路与竖向道理,相邻的道路之间相差(100m),从左到右第(i)条纵向街道和从下到上第(j)条横向街道之间的交点描述为((i,j)),在某些交点上建有以交点为圆心,半径是 (10) 米的喷泉,行走时不能穿过喷泉。

    问你要从((X_1,Y_2))走到((X_2,Y_2))最短要走多少?

    由于所有的喷泉横纵坐标都相等,所以显然走尽可能多的喷泉可以是路径更短,

    对于一个喷泉可以短(20-dfrac 1 4* 2pi r)

    至此问题完成转化:最长上升子序列问题

    不妨设(X_1<X_2,Y_1<Y_2),仅当(X_1<x_i<X_2,Y_1<y_i<Y_2)时候,统计这个点对答案的影响

    并把所有点按照横坐标排序,求(y_i)(Y_1)为开始,(Y_2)终止的最长上升子序列

    对于正常的(dp)做法,过不去的,需要用(nlog_n)的做法,我想,下文会提到的吧

    #include <bits/stdc++.h>
    #define LL long long
    #define debug
    using namespace std;
    
    const int N = 3e5+66;
    
    int n, ans, f[N];
    int sx, sy, tx, ty;
    
    struct node{int x, y;}a[N];
    
    inline int cmp(node s, node t){
       if (s.x == t.x) return s.y > t.y;
       if (sy < ty) return s.x < t.x;
       return s.x > t.x;
    }
    
    inline int thestars() {
       cin >> sx >> sy >> tx >> ty >> n;
       if (tx < sx) swap(sx, tx), swap(sy, ty);
       for (int i = 1; i <= n; ++ i) cin >> a[i].x >> a[i].y;
       sort(a+1, a+n+1, cmp);
       double mhd = tx - sx + abs(ty - sy);
       f[0] = -0x7fffffff;
       for (int i = 1; i <= n; ++ i) {
          if (a[i].x > max(sx, tx) || a[i].x < min(sx, tx) || a[i].y > max(sy, ty) || a[i].y < min(sy, ty)) continue;
          if (a[i].y > f[ans]) f[++ ans] = a[i].y;
          else if (a[i].y < f[ans]) {
             int pos = lower_bound(f+1, f+ans+1, a[i].y) - f;
             f[pos] = a[i].y;
          }
       }
       printf ("%.15lf", 100*mhd-ans*(20-5*M_PI));
       return 0;
    }
    
    int youngore = thestars();
    
    signed main() {;}
    

    第三题

    显然,三分图有以下性质:

    • 同一集合内,没有连边
    • 不存在一个点向同一个集合连两条边

    发现上面的性质好像只涉及到两个集合啊,因此答案呼之欲出:(calc(A,B)*calc(A,C)*calc(B,C))

    状态:设(f[i][j])表示一个集合有(i)个点,另一个集合有(j)个点的时候,炼成的三分图的个数

    转移:(f[i][j] = f[i][j-1]+f[i-1][j-1]*i)

    考虑第二个集合的最后一个点,他可能有什么情况,

    第一种,不连边,继承上一次的

    第二种,连边,则有(i)种连边方式,若练了某条边,则第一个集合对应的点就不能连其他边了,方案数为:(i*f[i-1][j-1])

    结果:(f[a][b]*f[b][c]*f[a][c])

    #include <bits/stdc++.h>
    #define int long long
    #define debug
    using namespace std;
    
    const int N = 3e3+66, mod = 998244353, M = 2000;
    
    int t, a, b, c;
    int f[N][N];
    
    inline int thestars() {
       cin >> t;
       for (int i = 1; i <= 3000; ++ i) {
          f[i][1] = i+1;
          for (int j = 2; j <= i; ++ j) 
             f[i][j] = (f[i][j - 1] + i*f[i - 1][j - 1]%mod)%mod;
       }
       for (int i = 1; i <= 3000; ++ i)
          for (int j = 1; j < i; ++ j)
             f[j][i] = f[i][j];
             while(t --> 0) {
                int a, b, c;
                cin >> a >> b >> c;
                cout << f[a][b]*f[a][c]%mod*f[b][c]%mod << '
    ';
             }
       return 0;
    }
    
    int youngore = thestars();
    
    signed main() {;}
    
    

    下午

    讲dp!!!

    我们来通过通过几道例题来体会一下什么是dp

    01背包

    将n件有着各自体积和价值的物品装入一个容积为m的背包中,求最大的总价值

    状态:(f[i][j])表示前(i)件物品放入背包为(j)的背包中所能获得的最大总价值

    转移:(f[i][j] = max(f[i-1][j], f[i-1][j-v[i]]+w[i]))

    结果:(f[n][m])

    最长不下降子序列

    给出一个长度为n 的序列,求最长的子序列,满足这些元素依次不减

    状态:设(f[i])表示以(i)为结尾的最长不下降子序列的最长长度

    转移:(f[i] = max(f[j]+1))其中(a[j]<a[i])

    结果:(max(f[i]))

    上面是(O(n^2))做法,还有一种(O(nlogn))的做法:

    状态:设(f[i])表示长度为(i)的的最长不下降子序列的最后一个元素的最小值

    举个例子:

    有序列(a[] = {8,2,3,5,7,6,4}),所以可得:

    (f[0] = 0,f[1] = 2, f[2] = 3, f[3]=5,f[4]=7)(第一遍扫)

    遇到(6)考虑更新(f[4]),遇到(4)考虑更新(f[3])

    至于为什么是logn的,因为每次是二分查找((lower)_(bound)是log的)

    再次考虑(dp)的牛逼之处: 需要有易于表示的状态,能够列出的转移,便于计算的结果

    要把式子推出来再去写代码

    下面有几道一般dp,没什么特点,就是

    渡河问题

    click

    状态:(f[i])表示将前(i)头牛运到对岸的时间

    转移:(f[i] = min(f[j]+2*M+sum[i-j]))其中(sum)为前缀和

    结果:(f[n])

    解题

    click

    给出贪心的(Hack)数据:

    50 5  
    40 10  
    10 40  
    10 5  
    10 3  
    10 2
    

    状态:(f[i][j])表示处理(1)(j)的题,最后一次选择了(i)(j)的最短月数

    转移:(f[i][j] = min(f[k][i-1]+1/2))其中剩下的钱足够就是(+1)否则是(+2)

    结果:(min(f[i][p])+1)

    晚上

    没时间写了啊,**白某飞主任

  • 相关阅读:
    使用python-gitlab包在gitlab上自动创建分组
    navicat连接远程mysql失败
    Python shell介绍
    Python任务流taskflow
    Python导包问题
    demo27-数组去重
    demo26-通过循环输出数据到页面显示
    demo25-for循环
    Visual Studio 2005 快捷键汇总
    三维立体图片效果
  • 原文地址:https://www.cnblogs.com/yszhyhm/p/13434999.html
Copyright © 2011-2022 走看看