zoukankan      html  css  js  c++  java
  • CF1225G To Make 1

    Link
    (a_i)总共除过(b_i)次,那么我们要做的就是找到一组(b)使得(sumlimits_{i=0}^na_ik^{-b_i}=1)
    显然存在合法的(b)就存在一组合法的合并方案,构造方法如下:

    每次选择两个(b_i)相同的最大的合并,然后递归进子问题。
    因为(a_i mid k),所以每次不可能只出现一个最大值,这样是肯定无解的。

    考虑状压dp,设(f_{s,x})表示存在一组(b)使得(sumlimits_{iin s}a_ik^{-b_i}=x)
    转移非常简单就不讲了,注意到复杂度是(O(2^nnk))会爆炸,用bitset优化即可做到(O(frac{2^nnk}{omega}))

    #include<queue>
    #include<cstdio>
    #include<bitset>
    #include<utility>
    #define se second
    const int N=2007,M=65537;
    using std::pair;
    using pi=pair<int,int>;
    int a[16],c[16],low[M],n,k,U,s;
    std::bitset<N>f[M];
    std::priority_queue<pi>q;
    int read(){int x;scanf("%d",&x);return x;}
    void dfs(int st,int x)
    {
        if(!st) return;
        for(;x*k<=s&&f[st][x*k];x*=k) for(int i=0;i<n;++i) if(st>>i&1) ++c[i];
        for(int i=0;i<n;++i) if(st>>i&1&&x>=a[i]&&f[st^1<<i][x-a[i]]) return dfs(st^1<<i,x-a[i]);
    }
    int main()
    {
        n=read(),k=read(),U=(1<<n)-1,f[0][0]=1;
        for(int i=0;i<n;++i) s+=(a[i]=read()),low[1<<i]=i;
        for(int i=1;i<=U;++i) low[i]=low[i&-i];
        for(int i=1;i<=U;++i)
        {
    	for(int j=0;j<n;++j) if(i>>j&1) f[i]|=f[i^1<<j]<<a[j];
    	for(int j=s/k;j;--j) if(f[i][j*k]) f[i][j]=1;
        }
        if(!f[U][1]) return puts("NO"),0;
        puts("YES"),dfs(U,1);
        for(int i=0;i<n;++i) q.push({c[i],a[i]});
        for(pi u,v;q.size()>1;)
        {
    	u=q.top(),q.pop(),v=q.top(),q.pop(),printf("%d %d
    ",u.se,v.se),u.se+=v.se;
    	while(!(u.se%k)) u.se/=k,--u.first;
    	q.push(u);
        }
    
    }
    
  • 相关阅读:
    leetcode 第二题Add Two Numbers java
    二叉树中的那些常见的面试题(转)
    运行的指令
    Python常见经典 python中if __name__ == '__main__': 的解析
    软件测试基本概念
    JAVA Android王牌教程
    17个新手常见Python运行时错误
    QTP
    链表有关的常见面试题
    Robot Framework and Ride
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12246968.html
Copyright © 2011-2022 走看看