简单题
D. Cunning Gena
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define MAXN 22
ll dp[1<<MAXN];
int x[150];
ll k[150];
int M[150];
int d[150];
int id[150];
ll n,m,b;
int main()
{
scanf("%lld%lld%lld",&n,&m,&b);
int lim=1<<m;
for(int i=1;i<=n;i++)
{
scanf("%d%lld%d",x+i,k+i,M+i);
for(int j=0;j<M[i];j++)
{
int t;scanf("%d",&t);
d[i]|=1<<(t-1);
}
id[i]=i;
}
sort(id+1,id+1+n,[=](int x,int y)->bool{
return k[x]<k[y];});
for(int i=0;i<lim;i++)
dp[i]=2e18;
//cout<<dp[0]<<endl;
dp[0]=0;
ll ans=dp[1];
ll inf=ans;
for(int t=1;t<=n;t++)
{
int i=id[t];
for(int j=0;j<lim;j++)
{
if(dp[j]==inf)continue;
dp[j|d[i]]=min(dp[j|d[i]],dp[j]+1ll*x[i]);
}
ans=min(ans,dp[lim-1]+1ll*b*k[i]);
}
if(ans==inf)ans=-1;
cout<<ans<<endl;
}
思维好题
题意:给你n个物品(n<=24),每个物品有一个体积 v i v_i vi,一个箱子最多能容纳V体积,问最少需要几个箱子?
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define MAXN 24
int d[1<<MAXN];
int p[1<<MAXN];
int a[1<<MAXN];
int s[MAXN+3];
int lowbit(int x)
{
return x&(-x);
}
int main() {
ll n,k;scanf("%lld%lld",&n,&k);
for(int i=0;i<n;i++) {
scanf("%d", a +(1<<(i)));
}
int lim=1<<n;
s[0]=1;
for(int i=1;i<n;i++)
s[i]=s[i-1]<<1;
for(int i=0;i<lim;i++) {
d[i]=p[i] =30;
}
d[0]=0;
p[0]=k;
for(int j=1;j<lim;j++) {
int tmp=j;
while(tmp)
{
int cur=lowbit(tmp);
int nxt = j^cur;
int cnt = d[nxt];
int mod = p[nxt];
if (mod + a[cur] > k)
{
cnt++;
mod = a[cur];
//我一开始写的是mod=min(mod,a[cur]);,但这样也可以过
}
else
mod += a[cur];
if (cnt < d[j]|| cnt == d[j]&& mod < p[j]) {
d[j] =cnt;
p[j]=mod;
}
tmp-=cur;
}
}
cout<<d[lim-1]-1<<endl;
}
卡常数有点毒瘤,首先我用了一个数组表示一个状态的最小需要体积。
那么用到的箱子数量就是dp[i]/k+(dp[i]%k>0),但是由于用到了除法常数有点大。
所以我比赛时候被卡了。
正解应该是开两个数组。。。。
一个记录状态的箱子数量,一个记录状态的当前使用箱子已用体积。
这样就可以避免除法了。
然后,这里有一个很妙的点在于:
其实这个2^nn得递推,做到了类似于全排列n!的效果。
即囊括了所有可能的先后顺序。
然后这题还卡常数,实测lowbit快于每一位的枚举,这样才100%通过*