LOADING

加载过慢请开启缓存,浏览器默认开启

daily 3

2023/4/18 daily

今天阿里下书面offer了,全心等鹅中

做了3道背包,明天复习一下背包和状压

CF 837D

给你一堆数,求乘积中0的数量最多的数,set的大小为k

几个数相乘之后的数的0的个数取决于2和5的因数的数量
先处理出来,然后
$dp[i][j][k]$表示前i个数中选择了j个数,且5的数量为k,2的数量为dp[i][j][k],转移就很清楚了

void solve(){
  int n,k;
  cin>>n>>k;
  vector<ll>num(n+1),fac5(n+1),fac2(n+1);
  for(int i=1;i<=n;++i){
    cin>>num[i];
    ll& x=num[i];
    while(x%5==0){
        fac5[i]++;
        x/=5;
    }
    while(x%2==0){
        fac2[i]++;
        x/=2;
    }
  }
  vector dp(n+1,vector<ll>(N,-INF));
  dp[0][0]=0;
  for(int i=1;i<=n;++i){
    for(int j=k;j>=1;--j){
        for(int l=N-1;l>=fac5[i];--l){
            if(num[i]){
                dp[j][l]=max(dp[j-1][l-fac5[i]]+fac2[i],dp[j][l]);
            }
        }
    }
  }
  ll ans=0;
  for(ll i=0;i<N;++i){
    ans=max(ans,min(i,dp[k][i]));
  }
  cout<<ans<<'\n';
  return;
}

CF 755F

首先我们可以发现(指看了题解发现)原关系可以形成很多不同大小的环,那么对于奇数长度的环,我们可以减少${(len/2)+1}$个元素来让之中每个人都没法获得礼物,对于偶数长度的环,这个值则是${len/2}$,那么,我们可以直接01背包开始选喽,但是这样会超时,正确的做法是把每个长度相同的环做成状态压缩之后再选即可

void solve(){
  int n,k;
  cin>>n>>k;
  vector<int>vis(n+1),a(vis),num(vis),lens(vis),v(vis);//num: number of rings that has length i,lens: length of i ring
  int cnt=0;//count of total rings;(distinct size)
  for(int i=1;i<=n;++i)cin>>a[i];
  for(int i=1;i<=n;++i){
    int now=i,len=0;
    while(!vis[now]){
        vis[now]=1;
        ++len;
        now=a[now];
    }
    if(num[len])num[len]++;
    else num[len]=1,lens[++cnt]=len;
  }
  ll ans=0;
  for(int i=1;i<=cnt;++i){
    ans+=lens[i]/2*num[lens[i]];
  }
  if(ans>=k){
    ans=k*2;
  }else{
    ans+=k;
  }
  ans=min(ans,(ll)n);
  int tot=0;
  for(int i=1;i<=cnt;++i){
    for(int j=1;j<=num[lens[i]];j<<=1){
        v[++tot]=j*lens[i];
        num[lens[i]]-=j;
    }
    if(num[lens[i]]){
        v[++tot]=num[lens[i]]*lens[i];
    }
  }
  bitset<N>dp;
  dp.set(0);
  for(int i=1;i<=tot;++i){
    dp|=(dp<<v[i]);
  }
  if(dp.test(k)){
    cout<<k<<' '<<ans<<'\n';
  }else{
    cout<<k+1<<' '<<ans<<'\n';
  }
  return;
}

CF 510D

一开始也没想出来,看题解了之后发现只要选择的数gcd=1就可以了。。。感觉自己好傻逼,那么用map优化一下空间复杂度就好了

int gcd(int a,int b){return b?gcd(b,a%b):a;}
void solve(){
  int n;cin>>n;
  vector<int>l(n),c(n);
  for(int i=0;i<n;++i)cin>>l[i];
  for(int i=0;i<n;++i)cin>>c[i];
  map<int,int>dp;
  dp[0]=0;
  for(int i=0;i<n;++i){
    for(auto& k:dp){
        int tmp=gcd(l[i],k.first);
        if(dp[tmp]!=0){
            dp[tmp]=min(dp[tmp],k.second+c[i]);
        }else{
            dp[tmp]=k.second+c[i];
        }
    }
  }
  cout<<(dp.count(1)?dp[1]:-1)<<'\n';
  return;
}