• 第一次爆零


    前言:打代码慢没关系,除非你不用心

    一开始打了好多,但由于孙姓同学(gavensun.com)运行了一个恶意程序,然后本篇博文并没有保存,所以前言就说这么多

    第一题,注意数据范围,不要吊儿郎当,原题也要打好

    第二,三题(并查集求联通块:不要乱写,撞对垃圾样例并不一定对

    2

     道路

                    1000ms/128MB
      M市有 n个城镇,同时有 m条道路(无向),城镇之间可以通过一条或多条道路到达。为了全面建设小
      康社会,现要新建设一些道路,使得所有城镇之间两两可以互相到达。
      请你计算出最少还需要建设多少条道路

      输入格式:
      第一行:两个正整数,分别是城镇数目 n(n<1000)和道路数目 m(m <= n * (n – 1)/2));随后的
      m行对应 m条道路,每行给出两个正整数,分别是道路相连的两个城镇编号。城镇从 1到 N编号。
      两个城市间可以有多条道路相通。

      输出格式:一行一个整数。为最少需要建设的道路。

       

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define DEEEEEEEE
     4 using namespace std;
     5 const int MAXN = 1000+9;
     6 const int MAXM = 500000+9;
     7 
     8 int n,m,ans;
     9 int fa[MAXN];
    10 bool visit[MAXN];
    11 
    12 int father(int x) {
    13     if(x == fa[x]) return x;
    14     return fa[x] = father(fa[x]);
    15 }
    16 
    17 int main() {
    18     #ifdef DEEEEEEEE
    19         freopen("b.in","r",stdin);
    20         freopen("b.out","w",stdout);
    21     #endif
    22     scanf("%d%d",&n,&m);
    23     for(int i = 1; i <= n; i++) fa[i] = i;
    24     int fx,fy;
    25     for(int i = 1, x, y; i <= m; i++) {
    26         scanf("%d %d",&x,&y);
    27         fx = father(x), fy = father(y);
    28         fa[fx] =fy;//把道路的代表元素联通 
    29     }
    30     for(int i = 1; i <= n; i++) { // 求联通块个数 
    31         if(!visit[father(i)]) {//先写father(i) 这才把fa[i]算出来 
    32             visit[fa[i]] = 1;
    33             ans++;
    34         }
    35     }
    36     printf("%d",ans-1);//ans个联通块,最少需要连ans-1条道路 
    37     return 0;
    38  }

    3.

      现在一个平面上画了 n 个矩形。每一个矩形的两边都与坐标轴相平行,且矩形定点的坐标均为整数。现定
      义满足如下性质的图形为一个块:
      1. 每一个矩形都是一个块;
      2. 如果两个块有一段公共的部分,那么这两个块就会形成一个新的块,否则这两个块就是不同的。
      示例:
      图 1矩形形成了两个不同的块。图 2矩形形成了一个块。

    找不同块的个数

    #include<cstdio>
    #include<algorithm>
    #define DEEEEEEEE
    using namespace std;
    const int MAXN = 7000+9;
    int n,ans;
    int fa[MAXN];
    bool visit[MAXN];
    
    int father(int x) {
        if(x == fa[x]) return x;
        return fa[x] = father(fa[x]);
    }
    
    struct node{
        int x1,y1,x2,y2;
    }e[MAXN];
    
    bool judge(int x1,int y1, int x2, int y2, int x111, int y111, int x222, int y222) {
        //找关系的时候冷静一点,不要慌 
        if(x2<x111 || x1>x222 || y1>y222 || y2<y111 ) return 0;//没有一点相交 
        if( (x1==x222 || x2==x111) && (y1==y222 || y2==y111) ) return 0;//相交一点 
        return 1;
    }
    
    int main() {
        #ifdef DEEEEEEEE
            freopen("c.in","r",stdin);
            freopen("c.out","w",stdout);
        #endif
        scanf("%d",&n);
        for(int i = 1; i <= n; i++) fa[i] = i;
        int x1,y1,x2,y2,x111,y111,x222,y222;
        // 矩形1号         矩形2号 
        int f1,f2;
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            e[i].x1 = x1, e[i].x2 = x2, e[i].y1 = y1, e[i].y2 = y2;
            for(int j = 1; j < i; j++) {
                x111 = e[j].x1 , y111 = e[j].y1 , x222 = e[j].x2 , y222 = e[j].y2 ;
                if(judge(x1,y1,x2,y2,x111,y111,x222,y222) ) {
                    f1 = father(i), f2 = father(j);
                    fa[f1] = f2;
                }
            }
        } 
        for(int i = 1; i <= n; i++) {
            if(!visit[father(i)]) {
                visit[fa[i]] = 1;
                ans++;
            }
        }
        printf("%d",ans);
        return 0;
     }

    第四题:分层图(仔细分析题目,不要看见那么多的条件就害怕

    貌似在luogu上有这题,不过这题它好像改编了(DP

                消失的 c题(c.cpp/c.in/c.out)
                1000ms/128MB
      题目描述
      N 个虫洞,M 条单向跃迁路径。从一个虫洞沿跃迁路径到另一个虫洞需要消耗一定量的燃料和 1 单
      位时间。虫洞有白洞和黑洞之分。设一条跃迁路径两端的 虫洞质量差为 delta。
      1.从白洞跃迁到黑洞,消耗的燃料值减少 delta,若该条路径消耗的燃料值变为负数的话,取为 0。
      2.从黑洞跃迁到白洞,消耗的燃料值增加 delta。
      3.路径两端均为黑洞或白洞,消耗的燃料值不变化。
      每过 1 单位时间黑洞变为白洞,白洞变为黑洞。
      在飞行过程中,可以选择在一个虫洞停留 1 个单位时间,如果当前为白洞,则不消耗燃料,否则消
      耗 s[i]的燃料。现在请你求出从 虫洞 1 到 N 最少的燃料消耗,保证一定存在 1 到 N 的路线。

      输入格式

      第 1 行:2 个正整数 N,M
      第 2 行:N 个整数,第 i 个为 0 表示虫洞 i 开始时为白洞,1 表示黑洞。
      第 3 行:N 个整数,第 i 个数表示虫洞 i 的质量 w[i]。
      第 4 行:N 个整数,第 i 个数表示在虫洞 i 停留消耗的燃料 s[i]。

      第 5..第 M+4 行:每行 3 个整数,u,v,k,表示在没有影响的情况下,从虫洞 u到虫洞 v 需要消耗燃料 k。 


      输出格式
      一个整数,表示最少的燃料消耗。

      样例输入
      4 5
      1 0 1 0
      10 10 100 10
      5 20 15 10
      1 2 30
      2 3 40
      1 3 20
      1 4 200
      3 4 200

      

      样例输出
      130

      数据范围
      对于 30%的数据: 1<=N<=100,1<=M<=500
      对于 60%的数据: 1<=N<=1000,1<=M<=5000
      对于 100%的数据: 1<=N<=5000,1<=M<=30000
      其中 20%的数据为 1<=N<=3000 的链
      1<=u,v<=N, 1<=k,w[i],s[i]<=200

      样例说明
      按照 1->3->4 的路线。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<queue>
     4 #define DEEEEEEEE
     5 using namespace std;
     6 const int MAXN = 10000+99;
     7 const int MAXM = 90000+99;
     8 const int INF = 2147000047;
     9 
    10 int n,m,cnt,head[MAXN],dis[MAXN],vis[MAXN];
    11 int wb[MAXN];//wb[i] 为0表示i开始为白洞,1表示黑洞
    12 int w[MAXN];//i的质量
    13 int s[MAXN];//停留时的消耗能量 
    14 
    15 struct edge{
    16     int next,y,val;
    17 }e[MAXM];
    18 
    19 void add_edge(int x, int y, int val) {
    20     e[++cnt].y = y;
    21     e[cnt].val = val;
    22     e[cnt].next = head[x];
    23     head[x] = cnt;
    24 }
    25 
    26 struct node{
    27     int id,dis;
    28     node (int id = 0, int dis = 0) : id(id) , dis(dis){}
    29     bool operator < (const node &xx) const {
    30         return dis > xx.dis ;
    31     }
    32 };
    33 priority_queue <node> q;
    34 
    35 int abs(int x, int y) {
    36     if(x > y) return x - y;
    37     else return y - x;
    38 }
    39 
    40 void init() ;
    41 int main() {
    42     #ifdef DEEEEEEEE
    43         freopen("c.in","r",stdin);
    44         freopen("c.out","w",stdout);
    45     #endif
    46     init();
    47     for(int i = 1; i <= n*2; i++) dis[i] = INF;
    48     dis[1] = 0;
    49     q.push(node(1,0)) ;
    50     while(!q.empty() ) {
    51         node tmp = q.top() ;
    52         q.pop();
    53         int now = tmp.id ;
    54         if(vis[now]) continue;
    55         vis[now] = 1;
    56         for(int i = head[now]; i; i = e[i].next ) {
    57             int y = e[i].y;
    58             int dalta = abs(w[now] , w[y]);
    59             if(wb[now]==0 && wb[y]==1) dalta = max(0, e[i].val - dalta);
    60                 else if(wb[now]==1 && wb[y]==0) dalta = e[i].val + dalta;
    61             else dalta = e[i].val ;
    62             
    63             if(y > n) y -= n;
    64             else y += n;//注意换图 
    65             
    66             if(dis[y] > tmp.dis + dalta) {
    67                 dis[y] = tmp.dis + dalta;
    68                 q.push(node(y,dis[y])); 
    69             }
    70         }
    71         //下面考虑的是停留的情况 
    72         int t = 0, nn = now;
    73         if(wb[now] == 1) t = s[now];//t是真正停留花费的能量 
    74         if(nn > n) nn -= n;
    75         else nn += n;//依然是换图 
    76         if(dis[nn] > tmp.dis + t) {
    77             dis[nn] = tmp.dis + t;
    78             q.push(node(nn,dis[nn])); 
    79         }
    80     } 
    81     printf("%d",min(dis[n], dis[n+n]));//比较两图之后再输出 
    82     return 0;
    83  }
    84  
    85 void init() {
    86     scanf("%d%d",&n,&m);
    87     for(int i = 1; i <= n; i++) scanf("%d",&wb[i]) , wb[i+n] = wb[i] ^ 1; 
    88     for(int i = 1; i <= n; i++) scanf("%d",&w[i]) , w[i+n] = w[i];
    89     for(int i = 1; i <= n; i++) scanf("%d",&s[i]) , s[i+n] = s[i];
    90     int x,y,val;
    91     for(int i = 1; i <= m; i++) {
    92         scanf("%d%d%d",&x,&y,&val);
    93         add_edge(x,y,val);
    94         add_edge(x+n,y+n,val);
    95         /*不能再无脑地将上下两个图联通,因为还要考虑当前点是白洞,可能不耗能
    96         这里的两个图只是黑白颠倒的,因为每次跃迁时都会花费 1 单位时间,所以每次都要换图*/
    97     }
    98 }

     下面是我们亲爱的庆鸽鸽的SPFA版,特意再次发出,表示感谢, 同时,缅怀一下我第一个学会的最短路算法——SPFA(本人一开始认为floyd太麻烦,没记...

    #include <cstdio>
    #include <queue>
    #include <algorithm>
    #include <cstring>
    
    #define MAXN 11111
    #define MAXM 111111
    
    int n, m, cnt;
    int p[MAXN], w[MAXN], s[MAXN];
    int vis[MAXN], dis[MAXN], head[MAXN];
    std::queue <int> q;
    
    struct edge {
        int y, val, next;
        edge(int y = 0, int val = 0, int next = 0) : y(y), val(val), next(next) {}
    }e[MAXM];
    
    inline void add_edge(int x, int y, int z) {
        e[++cnt] = edge(y, z, head[x]); head[x] = cnt;
    }
    
    int abs(int x) {
        return x >= 0 ? x : -x;
    }
    
    int main() {
        freopen("c.in", "r", stdin);
        freopen("c.out", "w", stdout);
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) scanf("%d", &p[i]), p[i + n] = p[i] ^ 1;
        for(int i = 1; i <= n; i++) scanf("%d", &w[i]), w[i + n] = w[i];
        for(int i = 1; i <= n; i++) scanf("%d", &s[i]), s[i + n] = s[i];
        for(int i = 1, x, y, z; i <= m; i++) {
            scanf("%d%d%d", &x, &y, &z);
            add_edge(x, y, z);
            add_edge(x + n, y + n, z);
        }
        for(int i = 0; i <= n * 2; i++) dis[i] = -1;
        q.push(1);
        vis[1] = 1;
        dis[1] = 0;
        while(!q.empty()) {
            int now = q.front(); q.pop();
            vis[now] = 0;
            for(int i = head[now]; i; i = e[i].next) {
                int nn = e[i].y, tmpn = nn;
                int del = abs(w[now] - w[nn]);
                if(nn > n) nn -= n;/////////////////
                else nn += n;///////////////
                if(!p[now] && p[tmpn]) del = std::max(0, e[i].val - del);
                else if(p[now] && !p[tmpn]) del = e[i].val + del;
                    else del = e[i].val;
                if(dis[nn] == - 1 || dis[nn] > dis[now] + del) {
                    dis[nn] = dis[now] + del;
                    if(!vis[nn]) {
                        vis[nn] = 1;
                        q.push(nn);
                    }
                }
            }
            
            int t = 0, nn = now;
            if(p[now]) t = s[now];
            if(nn > n) nn -= n;
            else nn += n;
            if(dis[nn] == - 1 || dis[nn] > dis[now] + t) {
                dis[nn] = dis[now] + t;
                if(!vis[nn]) {
                    vis[nn] = 1;
                    q.push(nn);
                }
            }
        }
        printf("%d
    ", std::min(dis[n], dis[n + n]));
        return 0;
    }

    第五题:DP( 好好学习,好好做人,不要好高骛远,请脚踏实地

                            杆子(e.cpp/e.in/e.out)
                            1000ms/256MB
      题目描述
      现在有 n个高矮不同的杆子,第 i个杆子高度为 i。
      有许多的方案能够将这 n个杆子排成一排。
      从最左边看和从最右边看这一排 n个杆子分别能看到一定数目的杆子(高的杆子会挡住矮的杆子)。
      现在问从左端看能看见 L根,同时从右端看能看见 R根的方案数有多少
    %1000000007

    输入格式
    一个 n
    之后 n个数为杆子的高度

    输出格式
    方案数

      样例输入
      4 1 2

      (高度应该都是1 ~ n)

      样例输出
      2

      样例解释
      4 1 2 3
      4 2 1 3

      对于 40 %的数据 N <= 11;
      对于 90 % 的数据 N <= 400,L,R <= N
      对于 100 % 的数据 N <= 600

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 //#define DEEEEEEEE
     5 using namespace std;
     6 const int MOD = 1000000007 ;
     7 const int MAXN = 600+9;
     8 
     9 int n,L,R;
    10 int hi[MAXN];
    11 unsigned long long d[2][MAXN][MAXN];
    12 /*d[MAXN][MAXN][MAXN] : d[i][j][k] 表示 前i个杆子摆放成: 从左边看见j个, 从右边看见k个 的方案数
    13  我们不妨每次认为放的都是最矮的(矮和高放的顺序是随意的,因为总要放满n个杆子,这样好写状态转移罢了)
    14  有:  d[i][j][k] = d[i-1][j-1][k] + d[i-1][j][k-1] + d[i-1][j][k]*(i-2) / 第i个杆子放在最左边的方案数 + 放在最右边的方案数 + 放在中间的方案数
    15  注意:内存会炸掉 !! 仔细观察后,发现该 状态转移方程 只用到了当前状态 和 上一状态 这两个状态,所以可以用滚动数组优化
    16  (细节见代码,好像没有什么细节的...只需想好状态转移
    17 */ 
    18 
    19 inline unsigned int g(int x) {return x-( (x>>1)<<1);} // 实际上就是一个 i % 2 ,只是比较快 
    20 
    21 int main() {
    22     #ifdef DEEEEEEEE
    23         freopen("e.in","r",stdin);
    24         freopen("e.out","w",stdout);
    25     #endif
    26     scanf("%d%d%d",&n,&L,&R);
    27     d[1][1][1] = 1;//初始化 
    28     for(int i = 2; i <= n; i++) 
    29         for(int j = 1; j <= i; j++) 
    30             for(int k = 1; k <= i; k++) //这里都是前i个 
    31                 d[g(i)][j][k] = ( d[g(i-1)][j-1][k] + d[g(i-1)][j][k-1] + d[g(i-1)][j][k]*(i-2) )% MOD;
    32     
    33     cout << d[g(n)][L][R]; 
    34      return 0;
    35  }

    完结撒花!!!希望不要在犯哦

  • 相关阅读:
    SPOJ_DSUBSEQ Distinct Subsequences
    ZOJ 3791 An easy game DP+组合数
    UVALive 4287 SCC-Tarjan 加边变成强连通分量
    ZOJ 3795 Grouping 强连通分量-tarjan
    HDU 4915 多校5 Parenthese sequence
    ZOJ 3790 Consecutive Blocks
    HDU 4866 多校1 主席树+扫描线
    求最大值及其下标
    查找整数
    抓老鼠
  • 原文地址:https://www.cnblogs.com/tyner/p/10809328.html
Copyright © 2020-2023  润新知