ACM-ICPC 2018 南京赛区网络预赛

                                                                       E.AC Challenge

题目链接:https://nanti.jisuanke.com/t/30994

题意:你有n个题要去做,你其实都会做但是要求是先做完某些题你才能做这道,每道题做后得分是第n次做题*a[i]+b[i],问你最后最大能得多少分

思路:第一开始去向网络流,但仔细想想他和时间还有关系,由于数据量只有20,果断去想DP,我们用二进制去存某些题做过没有,dp[i],i是二进制表示法确定做了那些题,dp[i]表示做这些题最大得多少分,我们用二进制去存好题与题得关系,我们用lowbit去数他完成了几道题,然后去返回这回是该做第几道,那么就简单得去状态压缩就好了,每次看i是否满足我们想做得当前题,如果满足我们就去把他得dp[i+1<<j]更新即可

状态转移方程是dp[i+(1<<j)]=max(dp[i+(1<<j)],dp[i]+做j题得到得分数);

当时又个毛病就是用define 去定义long long 之后我开数组得时候用了maxn+5 使得左移符号运算优先级低于+,导致内存超限,各种后悔

下面上代码

#include<bits/stdc++.h>
#define maxn 1<<20
#define ll long long
using namespace std;

ll dp[maxn];
int a[25],b[25],d[25];

int su(int x)
{
    int cnt=0;
    while(x){
        x-=x&-x;
        cnt++;
    }
    return cnt+1;
}

int main()
{
    int n,x,y;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d%d%d",&a[i],&b[i],&x);
        while(x--){
            scanf("%d",&y);
            d[i]+=1<<(y-1);
        }
        //cout<<i<<endl;
    }
    ll now=(1<<n)-1;
    for(int i=0;i<=now;i++){
            if(dp[i]==0&&i!=0)continue;
        for(int j=0;j<n;j++){
            if((i&(1<<j))==0&&(i&d[j])==d[j]){
                dp[i+(1<<j)]=max(dp[i+(1<<j)],dp[i]+su(i)*a[j]+b[j]);
            }
        }
    }
    ll ans=0;
    for(int i=0;i<=now;i++)
        ans=max(dp[i],ans);
    printf("%lld\n",ans);
    return 0;
}
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值