2019 牛客多校 第六场

题目链接:https://ac.nowcoder.com/acm/contest/886#question 链接

 

A:

  题意:签到,读题读了好久......

 

D:

  题意:给定n个物品,k个体积相等的盒子,求一个最小体积使得所有的物品都可以装到盒子里。装盒子要满足有大的就装大的,没有大的才能装小的的策略

  题解:我们要求的答案不满足:若ans成立,则ans+1成立(即不符合单调性)。

     对于下面这个样例

     15 5

     39 39 39 39 39 60 60 60 60 60 100 100 100 100 10

     199 为一个合法的答案,但 200 不是,201 也不是。

     这个数据量,直接暴力枚举ans,再判断是否满足即可。

     multiset的相关操作:https://blog.csdn.net/hlsdbd1990/article/details/46501391

               http://c.biancheng.net/view/545.html

#include <bits/stdc++.h>
using namespace std;

const int MAXN=1e3+5;
int n, k, a[MAXN], vis[MAXN];

bool judge1(int ans) //372ms
{
    sort(a, a+n);
    for(int i=0; i<n; i++) vis[i]=0;
    for(int i=0; i<k; i++)
    {
        int nv=ans;
        for(int j=n-1; j>=0; j--)
        {
            if(!vis[j] && nv>=a[j])
            {
                nv-=a[j];
                vis[j]=1;
            }
        }
    }
    for(int i=0; i<n; i++)
            if(!vis[i]) 
                return false;
    return true;
}

bool judge2(int ans) //310ms
{
    multiset<int> S;
    multiset<int>::iterator it;
    for(int i=0; i<n; i++) S.insert(a[i]);
    for(int i=0; i<k; i++)
    {
        int nv=ans; 
        while(!S.empty() && (it=S.upper_bound(nv))!=S.begin())
        {
            it--;
            nv-=*it;
            S.erase(it);
        }
    }
    return S.empty();
}

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int T, kase=0;
    for(cin>>T; T--; )
    { 
        cin>>n>>k;
        int sum=0, mv=0;
        for(int i=0; i<n; i++)
        {
            cin>>a[i];
            sum+=a[i];
            mv=max(mv, a[i]);
        }
        for(int ans=max(mv, (int)ceil(sum/k)); ans; ans++)
        {
            if(judge2(ans))
            {
                cout<<"Case #"<<++kase<<": "<<ans<<endl;
                break;
            }
        }
    }
    return 0;
}
View Code

 

J:

  题意:有i个技能,每次从j-1级升级到j级都有花费cij,然后所有技能都达到j级(至少有一个是j级,其他的可以大于等于j级)送dj块钱(cij和dj可以是负数),问你最多能赚多少。

  题解:用st表维护升级花费矩阵的前缀和,枚举可以可以达到的等级,注意可以达到等级从0开始,建表的时候把0也带上, 求最优情况即可。复杂度:n*m*logm+n*m ,960ms

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
const int MAXN=1e3+5;
int n, m;
ll b[MAXN], a[MAXN][MAXN], st[MAXN][MAXN][20];
  
void make_st()
{
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m+1; j++)
            st[i][j][0]=a[i][j];
 
    for(int k=1; k<=n; k++)
        for(int j=1; (1<<j)<=m; j++)
            for(int i=0; i+(1<<j)-1<=m; i++)
                st[k][i][j]=min(st[k][i][j-1], st[k][i+(1<<j-1)][j-1]);
}
 
ll ask(int i, int l, int r)
{
    int k=log2(r-l+1);
    return min(st[i][l][k], st[i][r-(1<<k)+1][k]);
}
 
int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int T, kase=0;
    for(cin>>T; T--; )
    {
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=m; j++)
            {
                cin>>a[i][j];
                a[i][j]=a[i][j]+a[i][j-1];
            }
        for(int i=1; i<=m; i++)
        {
            cin>>b[i];
            b[i]=b[i]+b[i-1];
        }
        make_st();
        ll ans=0;
        for(int i=0; i<=m; i++)
        {
            ll s1=0;
            for(int j=1; j<=n; j++)
                s1=s1+ask(j, i, m);
            for(int j=1; j<=n; j++)
            {
                ll s2=s1-ask(j, i, m)+a[j][i];
                ans=max(ans, b[i]-s2);
            }
        }
        printf("Case #%d: %lld\n", ++kase, ans);   
    }
    return 0;
}
View Code

 

posted @ 2019-08-05 22:16  N_Yokel  阅读(183)  评论(0编辑  收藏  举报