zoukankan      html  css  js  c++  java
  • P2170 选学霸

    传送门

    思路:

      ① 可以把每个学生都看作点,而那些实力相同的学生就处在同一个连通块内,因为连通块内的同学要么都取,要么不取,所以可以将连通块缩成一个点。只需用并查集维护每个连通块的大小。

      ② 接着采取神奇的可行性DP:用 f[ i ] 判断选出 i 个学生的方案是否可行。可行就转移 。

      伪代码:

        初始化: f[ 0 ] =true;

        for( j: 1~n ) //枚举点

          for( i: n-size ~0 ) //逆序,,

            if( f[ i ] )

              f [ i - size ] =true.( size 为枚举到的点大小)

      ③ 最后只要暴力地从 m 左右两边找出离 m 最近的  f[ i ] == true,就是答案。

    Code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<deque>
    #include<map>
    #include<set>
    using namespace std;
    #define lck_max(a,b) ((a)>(b)?(a):(b))
    #define lck_min(a,b) ((a)<(b)?(a):(b))
    typedef long long LL;
    const int maxn=4e5+7;
    inline LL lck_abs(LL a) {return a>0?a:-a;}
    inline LL read()
    {
        LL kr=1,xs=0;
        char ls;
        ls=getchar();
        while(!isdigit(ls))
        {
            if(!(ls^45))
                kr=-1;
            ls=getchar();
        }
        while(isdigit(ls))
        {
            xs=(xs<<1)+(xs<<3)+(ls^48);
            ls=getchar();
        }
        return xs*kr;
    }
    inline void out(LL xs)
    {
        if(!xs) {putchar(48); return;}
        if(xs<0) putchar('-'),xs=-xs;
        int kr[57],ls=0;
        while(xs) kr[++ls]=xs%10,xs/=10;
        while(ls) putchar(kr[ls]+48),ls--;
    }
    LL fa[maxn],si[maxn];//si 维护连通块大小
    inline LL find(LL u) 
    {
        return fa[u]==u?fa[u]:find(fa[u]);
    }
    LL n,m,k,u,v,i,j,l,r,ans,top,st[maxn];bool f[maxn];
    int main()
    {
        n=read();m=read();k=read();
        for(i=1;i<=n;i++)
            fa[i]=i,si[i]=1;
        for(i=1;i<=k;i++)
        {
            u=read();v=read();
            LL r1=find(u),r2=find(v);
            if(r1==r2) continue;
            fa[r2]=r1,si[r1]+=si[r2];
        }
        for(LL i=1;i<=n;i++)
            if(fa[i]==i) st[++top]=i;//缩点
        f[0]=true;
        for(i=1;i<=top;i++)//枚举点
            for(j=n-si[st[i]];j>=0;j--)//可达性DP 
                if(f[j])
                    f[j+si[st[i]]]=true;
        for(i=m;!f[i];i--); l=m-i;//找到比m小的最接近的人数
        for(i=m;!f[i];i++); r=i-m;//找到比m大的最接近的人数
        if(r>=l) out(m-l),putchar('
    ');
        else out(m+r),putchar('
    ');
    return 0;
    }
  • 相关阅读:
    第2章—装配Bean—通过java代码装配bean
    第2章—装配Bean—自动化装配Bean
    第1章—Spring之旅—Spring模块介绍
    第1章—Spring之旅—容纳你的Bean
    第1章—Spring之旅—简化Spring的java开发
    Spring由于web配置导致的spring配置文件找不到的问题的解决方案
    java中Filter过滤器处理中文乱码的方法
    JAVA的NIO的新特性和小Demo,进一步了解NIO
    Azure linux centos 默认登陆账号是什么?
    Linux 获取文件时间信息 判断文件是否存在
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9846429.html
Copyright © 2011-2022 走看看