• AT2346 No Need


    atcoder上的题目

    链接

    一道思维题目

    可以发现如果X是可有可无的,那么所有小于X的数也一定是可有可无的,

    所有我们只要找出最大的那个可有可无的数字就好了

    进一步分析,发现

    若A1, A2, . . . , Ai 的和为 S,当且紧当 Ai+1, Ai+2, . . . , AN 凑不出任何个 K − S 到 K − 1 之 间的数字, A1, A2, . . . , Ai 都是可有可无的。

    我们来不太严谨的证明一下

    若A1, A2, . . . , Ai 的和为 S,如果 Ai+1, Ai+2, . . . , AN 凑不出任何个 K − S 到 K − 1 之 间的数字,那么 A1, A2, . . . , Ai 都是可有可无的。

    这显然是成立的

    当sum=Ai+1, Ai+2, . . . , AN 凑出任何个 K − S 到 K − 1 之 间的数字时,我们一定有sum+s>=K

    我们从小到大将sum+s减去Ai,一定会有一个j使得sum+s<k那么Aj就一定不是可有可无的

    我们将A从小到大排序

    01背包就好了

    一个小技巧,0一定是可有可无的,所以循环到0是一定会输出,可以适当代码更加优美

    # include<iostream>
    # include<cstdio>
    # include<cmath>
    # include<algorithm>
    # include<cstring>
    using namespace std;
    const int mn = 5005;
    int a[mn];
    bool vis[mn];
    int n,k,s;
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
          scanf("%d",&a[i]);
          a[i]=min(a[i],k);
          s+=a[i];
        }
        sort(a+1,a+1+n);
        vis[0]=1;
        for(int i=n;i>=0;i--)
        {
            bool flag=false;
            for(int j=k-1;j>=k-s && j>=0;j--)
               if(vis[j]) {
               flag=true;
               break;
               }
            if(!flag) 
            {
                printf("%d",i);
                return 0;
            }
            for(int j=k;j>=a[i];j--)
               vis[j]=(vis[j] | vis[j-a[i]]);
            s-=a[i];
        }
        return 0;
    }
  • 相关阅读:
    SQL怎么随机提取出一条信息 mysql 获取随机记录
    css3 渐变 各浏览器兼容
    php的curl和socket的区别 转
    php获取本机真实IP地址
    SSH超时断开 ssh 老掉线
    php 获取远程服务器信息 get_headers 的使用
    如何删除右键菜单中的Catalyst(TM) Control Center选项
    多线程概念、案例!
    网络编程
    我的博客开通啦
  • 原文地址:https://www.cnblogs.com/logeadd/p/9295477.html
Copyright © 2020-2023  润新知