zoukankan      html  css  js  c++  java
  • 浅谈贪心【复习】

    NYG的背包

    【问题描述】

    NYG有一个神奇的背包,每放进去一个物品,背包的体积就会变大。

    也就是说,每放进一个物品,背包会被占用一定的体积,但是紧接着背包的总体积又会增大一定的值(注意是在放入物品后背包总体积才增大)。

    NYG发觉这个背包十分好用,于是不由自主地想到了一个问题。

    现在给出背包初始容量V 以及n个物品,每一个物品两个值a, b,分别表示物品所占体积 和放入背包后背包增大的体积。

    NYG想知道能否把所有物品装进去? 因为NYG比较老实,这么简单的问题自然装作不会做的样子。 于是他来请教你。

    分析:

    因为只问你能否装完,这就好办了多

    肯定需要把a<b的先用了,才可能搞得定a>b的

    如果前者都没法的话,更就别说后者

    对于a<b的部分,肯定是先用a较小的

    因为有可能只有把前几个空间赚回来了才能装下后面几个

    关键就在于a>b的情况

    这时发现肯定是亏空间的,考虑最优一定是先亏小空间,这样能腾出更多的空间为后面放

    读完题别以为是背包....

    code:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn = 100004;
    inline int read()
    {
        int ret, f=1;
        char c;
        while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')f=-1;
        ret=c-'0';
        while((c=getchar())&&(c>='0'&&c<='9'))ret = (ret<<3)+(ret<<1)+c-'0';
        return ret*f;
    }
    int T, n, s, cnt1, cnt2;
    struct thi{
        ll a, b;
    }t[maxn], f[maxn];
    bool cmp1(thi x, thi y)
    {
        return x.a < y.a;
    }
    bool cmp2(thi x, thi y)
    {
        return x.b > y.b;
    }
    int main()
    {
        T = read();
        while(T--)
        {
            n = read();s = read();
            cnt1 = cnt2 = 0;    
            for(int i = 1; i <= n; ++i)
            {
                ll x = 1LL * read(), y = 1LL * read();
                if(y > x)
                    t[++cnt1] = (thi){x, y};
                else
                    f[++cnt2] = (thi){x, y};
            }
            sort(t + 1, t + cnt1 + 1, cmp1);
            ll now = 1LL * s;    
            bool fl = 0;    
            for(int i = 1; i <= cnt1; ++i)
            {
                now -= t[i].a;
                if(now < 0)
                {
                    fl = 1;
                    break;
                }
                now += t[i].b;    
            }
            if(!fl)
            {
                sort(f + 1, f + cnt2 + 1, cmp2);
                for(int i = 1; i <= cnt2; ++i)
                {
                    now -= f[i].a;
                    if(now < 0)
                    {
                        fl = 1;
                        break;
                    }
                    now += f[i].b;    
                }
            }
            printf("%s
    ", fl? "No": "Yes");
        }
        return 0;
    }
    
    

    描述
    一张普通的国际象棋棋盘,它被分成 8 乘 8 (8 行 8 列) 的 64 个方格。设有形状一样的多米诺牌,每张牌恰好覆盖棋盘上相邻的两个方格,即一张多米诺牌是一张 1 行 2 列或者 2 行 1 列的牌。那么,是否能够把 32 张多米诺牌摆放到棋盘上,使得任何两张多米诺牌均不重叠,每张多米诺牌覆盖两个方格,并且棋盘上所有的方格都被覆盖住?我们把这样一种排列称为棋盘被多米诺牌完美覆盖。这是一个简单的排列问题,同学们能够很快构造出许多不同的完美覆盖。但是,计算不同的完美覆盖的总数就不是一件容易的事情了。不过,同学们 发挥自己的聪明才智,还是有可能做到的。

    现在我们通过计算机编程对 3 乘 n 棋盘的不同的完美覆盖的总数进行计算。

    这里写图片描述

    分析:

    首先奇数肯定无解,所以考虑偶数递推转移

    很明显设f[i]表示前i列的方案数

    只看两列的话只有三种方法

    所以有f[i]=f[i-2]*3

    但是有一种四列格子的会多出两种方案

    一种六列格子会多出两种方案

    所以转移就有

    f(n)=3f(n-2)+2f(n-4)+2f(n-6)+...+2f(0)

    f(n-2)= 3f(n-4)+2f(n-6)+......+2f(0)

    两式相减得到

    f(i)=4f(i-2)-f(i-4)

    递推转移就行

    代码就是一个递推式,就懒得写了

    分析:

    排完序后

    答案选的区间一定是一个连续的区间

    一个连续的区间什么时候取到最优解呢?

    当然是中位数了

    这样用尺取法双指针就可以做到O(n)判断了

    code by std:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define rep(i,n) for(int i=1;i<=n;++i)
    #define mp make_pair
    #define pb push_back
    #define x0 gtmsub
    #define y0 gtmshb
    #define x1 gtmjtjl
    #define y1 gtmsf
    long long s[100010];
    int n,k,a[100010],ans;
    bool check(int l,int r)
    {
        int x=(l+r)>>1;
        return (1ll*(x-l+1)*a[x]-(s[x]-s[l-1]))+((s[r]-s[x])-1ll*(r-x)*a[x])<=k;
    }
    int main()
    {
        freopen("signin.in", "r", stdin);
        freopen("signin.out", "w", stdout);
        scanf("%d%d",&n,&k);
        rep(i,n)scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        rep(i,n)s[i]=s[i-1]+a[i];
        int now=1;
        rep(i,n)
        {
            now=max(now,i);
            for(;now<=n&&check(i,now);now++);
            ans=max(ans,now-i);
        }
        printf("%d
    ",ans);
        return 0;
    }
    

    这题果然够签到的

    吐槽:最讨厌这种n又要考虑点,又要考虑边的题了

    假如说考虑将点x设为晴天点

    把该点之前的点和该点之后的点的贡献分别考虑

    将原式化简

    code by std

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #define N 1000005
    #define ll long long
    using namespace std;
    int n,d;
    int s[N];
    ll sum1[N],sum2[N],sum3[N],ans[N];
    ll work(int a,int b,int x){
    	ll s1,s2,s3;
    	if(a<=0||a>n) s1=sum1[b],s2=sum2[b],s3=sum3[b];
    	else s1=sum1[b]-sum1[a],s2=sum2[b]-sum2[a],s3=sum3[b]-sum3[a];
    	ll an=s3+(ll)2*s2*x+(ll)x*x*s1;
    	return an;
    }
    int main()
    {
    	scanf("%d%d",&n,&d);
    	for(int i=1;i<=n;i++) scanf("%d",&s[i]);
    	for(int i=1;i<=n;i++) sum1[i]=sum1[i-1]+s[i],sum2[i]=sum2[i-1]+(ll)i*s[i],sum3[i]=sum3[i-1]+(ll)i*i*s[i];
    	for(int i=1;i<=n+1;i++) ans[i]+=work(i-d-1,i-1,d-i+1);
    	for(int i=n;i>=1;i--) sum1[i]=sum1[i+1]+s[i],sum2[i]=sum2[i+1]+(ll)(n-i+1)*s[i],sum3[i]=sum3[i+1]+(ll)(n-i+1)*(n-i+1)*s[i];
    	for(int i=1;i<=n+1;i++) ans[i]+=work(i+d,i,d+i-n-1);
    	ll mx=0;
    	for(int i=1;i<=n+1;i++) mx=max(mx,ans[i]);
    	printf("%lld
    ",mx);
    	return 0;
    }
    

    https://www.luogu.org/problem/P4393

    题目描述

    对于一个给定的序列a1, …, an,我们对它进行一个操作reduce(i),该操作将数列中的元素ai和ai+1用一个元素max(ai,ai+1)替代,这样得到一个比原来序列短的新序列。这一操作的代价是max(ai,ai+1)。进行n-1次该操作后,可以得到一个长度为1的序列。

    我们的任务是计算代价最小的reduce操作步骤,将给定的序列变成长度为1的序列。

    分析:

    事实上每个数最多只可能被有效加两次(想一想,为什么

    合并一次后被另一个数合并,或者两边的数都比他小(如图a3)

    而看每一边的情况

    当一边的数都比a[i]小,最终一定会使a[i]被加一次,如果如图中a3,一侧有a1比a3大,显然在加上a1前会先和a3合并使得结果更优

    另一边同理

    code:

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int n;
    long long ans, a[1000100];
    int main()
    {
        cin >> n;
        for (int i = 0; i < n; i++){
            cin >> a[i];
        }
        for (int i = 1; i < n; i++){
            ans += max(a[i - 1], a[i]);
        }
        cout << ans;
    }
    
  • 相关阅读:
    Java compiler level does not match the version of the installed Java Project facet.
    Project configuration is not up-to-date with pom.xml. Select: Maven->Update Project... from the project context menu or use Quick Fix.
    JavaScript
    JavaScript
    Eclipse
    Eclipse
    Oracle
    Java
    Ext JS 4.2
    Eclipse
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11865610.html
Copyright © 2011-2022 走看看