潜龙未见静水流,沉默深藏待时秋。一朝破空声势振,惊世骇俗展雄猷。
随笔 - 80, 文章 - 0, 评论 - 3, 阅读 - 2065

CF1225G To Make 1 题解

目录

题目描述

给定 n 个数 ai ,保证 kai

f(x)x 除尽所有 k 的因子以后剩下的部分,每次你可以选择两个数 x,y ,然后将它们合并为一个数 f(x+y)

问能否将所有数合并成一个数 1 ,并输出方案。

数据范围

  • 2n16,2k2000
  • ai1,ai2000

时间限制 2s ,空间限制 512MB

分析

先给结论:合法当且仅当存在 bi0 ,满足 i=1naikbi=1

证明:

必要性 () 显然。

充分性 () :对 n 归纳,考虑 x=maxbi ,显然 x 至少在 b 中出现两次,将这两个数合并后转化为 n1 的问题。

构造方案用优先队列维护二元组 (a,b) 即可,每次挑 b 最大的两项合并。

接下来的目标是找到一组满足要求的 bi

dps,j 表示用了集合 s 中的数,能否通过选择 b 使得和为 j

转移分为两种:

  • 使用一个数 i ,转移方程 dp[s][j]|=dp[s^(1<<i)][j-a[i]]
  • 给所有 b 增加 1,转移方程 dp[s][j]|=dp[s][j*k]

第二维需要开到 i=1nai ,直接做时间复杂度 O(n2nai)2109 ,无法通过。

bitset 优化第一类转移,时间复杂度降至 O(n2naiw+2naik)

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>
using namespace std;
const int maxn=2005;
int k,n,sum;
int a[maxn],b[maxn];
bitset<maxn> dp[1<<16];
priority_queue<pii> q;
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++) scanf("%d",&a[i]),sum+=a[i];
    dp[0][0]=1;
    for(int s=1;s<1<<n;s++)
    {
        for(int i=0;i<n;i++) if(s>>i&1) dp[s]|=dp[s^(1<<i)]<<a[i];
        for(int j=sum/k;j>=1;j--) if(dp[s][j*k]) dp[s][j]=true;
    }
    if(!dp[(1<<n)-1][1]) printf("NO\n"),exit(0);
    printf("YES\n");
    for(int s=(1<<n)-1,j=1;s;)
    {
        int flg=0;
        for(int i=0;i<n;i++)
            if((s>>i&1)&&j>=a[i]&&dp[s^(1<<i)][j-a[i]])
            {
                flg=1,s^=1<<i,j-=a[i];
                break;
            }
        if(flg) continue;
        j*=k,assert(j<=sum&&dp[s][j]);
        for(int i=0;i<n;i++) if(s>>i&1) b[i]++;
    }
    for(int i=0;i<n;i++) q.push(mp(b[i],a[i]));
    while(q.size()>=2)
    {
        auto u=q.top();
        q.pop();
        auto v=q.top();
        q.pop();
        printf("%d %d\n",u.se,v.se);
        assert(u.fi==v.fi),u.se+=v.se;
        while(u.se%k==0) u.se/=k,u.fi--;
        q.push(u);
    }
    return 0;
}

posted on   peiwenjun  阅读(3)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示