Codeforces 题目传送门 & 洛谷题目传送门

还是做题做太少了啊……碰到这种题一点感觉都没有……

首先我们来证明一件事情,那就是存在一种合并方式 \(\Leftrightarrow\) \(\exist b_i\in\mathbb{Z}^+,\sum\limits_{i=1}^na_ik^{-b_i}=1\)

考虑充分性,倘若我们已经知道了 \(b_1,b_2,\dots,b_n\) 的值怎样构造合并的序列,考虑 \(B=\max\limits_{i=1}^nb_i\),这里有一个结论,那就是 \(b_i=B\) 的 \(i\) 至少有两个,否则,等式两边同时乘 \(k^B\) 可得 \(\sum\limits_{i=1}^na_ik^{B-b_i}=k^B\),而右边 \(k\mid k^B\),左边 \(\forall b_i<B,k\mid k^{B-b_i}\),又 \(k\nmid a_i\),故若满足 \(b_i=B\) 的 \(i\) 只有一个,那么 \(\sum\limits_{i=1}^na_ik^{B-b_i}\equiv a_i\not\equiv 0\pmod{k}\),矛盾。

此时假设 \(b_i=b_j=B\),那么我们合并 \(a_i,a_j\) 即可,假设 \(a_i+a_j=A\times k^{\alpha}\),那么 \(a_i,a_j\) 合并后就会变成 \(A\),而合并之后满足 \(\sum\limits_{i}a_ik^{-b_i}\) 的 \(b_i\) 依旧存在,因为 \(\dfrac{a_i}{k^B}+\dfrac{a_j}{k^B}=\dfrac{a_i+a_j}{k^B}=\dfrac{A}{k^{B-\alpha}}\),此时只需令其它 \(a_i\) 的 \(b_i\) 保持不变,新合并出的元素的 \(b\) 值为 \(B-\alpha\) 即可。如此合并 \(n-1\) 轮必定会得到一个数,这个数就是 \(1\)。

接下来考虑必要性,证明必要性等价于证明如果存在合法的合并方案,那么一定可以构造出合法的 \(b\) 序列。显然对于任意一种合并的局面,序列中每个数都可以看作原序列中一些数合并的结果,我们对于第 \(i\) 个数记这个集合为 \(S_i\),显然初始 \(S_i=\{i\}\)。我们构造初始 \(b_i=0\)。我们假设当前步合并了 \(a'_i,a'_j\) 两个元素,并且 \(a'_i+a'_j=A\times k^{\alpha}\),那么我们令 \(S_i,S_j\) 中所有元素的 \(b\) 值都增加 \(\alpha\)。这样构造出来有一个结论,那就是对于任意一个局面中的任意一个数 \(a'_i\),都有 \(a'_i=\sum\limits_{j\in S_i}a_jk^{-b_j}\),其中 \(a_j\) 为初始序列中下标为 \(j\) 的元素的值。这个结论显然可以归纳证明,对于初始局面显然满足,当我们合并两个数 \(a'_i,a'_j\) 时,\(A=\dfrac{a'_i+a'_j}{k^{\alpha}}=\dfrac{\sum\limits_{p\in S_i}a_pk^{-b'_p}+\sum\limits_{p\in S_j}a_pk^{-b'_p}}{k^{\alpha}}=\sum\limits_{p\in S_i}a_pk^{-b'_p-\alpha}+\sum\limits_{p\in S_j}a_pk^{-b'_p-\alpha}=\sum\limits_{p\in S_i\lor p\in S_j}a_pk^{-b_p}\),得证。又因为最终合并出来的数为 \(1\),最后合并出来的数对应的 \(S\) 显然为全集,故 \(\sum\limits_{i=1}^na_ik^{-b_i}=1\)。


这样就可以 \(dp\),此题 \(n\) 数据范围很小,故考虑状压 \(dp\),\(dp_{S,x}\) 表示考虑了 \(S\) 中的数,这些数和为 \(x\) 是否可行。转移比较容易,如果不能一眼看出转移的建议康下这个题。转移到 \(dp_{S,x}\) 可以新加入一个元素,即 \(dp_{S,x}|=dp_{S-\{u\},x-a_u}\),或者将序列中所有数都除以 \(k\),即 \(dp_{S,x}|=dp_{S,xk}\),复杂度 \(n2^n\sum a_i\approx 2\times 10^9\),会 TLE。不过注意到 \(dp\) 的每一个元素都是一个 bool 类型的数,故考虑 bitset 优化,复杂度可降到 \(\dfrac{n2^n\sum a_i}{\omega}+2^n\sum a_i\) 即可通过此题。

至于输出方案,就暴力找出 \(b\) 序列然后按照上述方式合并即可。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=16;
const int MAXV=2000;
const int MAXP=1<<MAXN;
int n,k,a[MAXN+5],b[MAXN+5],sum=0;
bitset<MAXV+5> bt[MAXP+5];
void getstate(int st,int x){
// printf("%d %d\n",st,x);
if(!st) return;
if(x*k<=sum&&bt[st][x*k]){
for(int i=1;i<=n;i++) if(st>>i-1&1) b[i]++;
getstate(st,x*k);return;
}
for(int i=1;i<=n;i++) if(st>>i-1&1){
if(x-a[i]>=0&&bt[st^1<<i-1][x-a[i]]){
getstate(st^1<<i-1,x-a[i]);return;
}
}
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum+=a[i];
bt[0][0]=1;
for(int i=0;i<(1<<n);i++){
for(int j=1;j<=n;j++) if(i>>j-1&1) bt[i]|=bt[i^1<<j-1]<<a[j];
for(int j=sum/k;j;j--) if(bt[i][j*k]) bt[i][j]=1;
}
if(!bt[(1<<n)-1][1]) puts("NO");
else{
puts("YES");getstate((1<<n)-1,1);
priority_queue<pii> q;
for(int i=1;i<=n;i++) q.push(mp(b[i],a[i]));
while(q.size()>1){
pii p1=q.top();q.pop();
pii p2=q.top();q.pop();
printf("%d %d\n",p1.se,p2.se);
p1.se+=p2.se;
while(p1.se%k==0) p1.se/=k,p1.fi--;
q.push(p1);
}
}
return 0;
}

Codeforces 1225G - To Make 1(bitset+状压 dp+找性质)的更多相关文章

  1. Codeforces Gym 100015F Fighting for Triangles 状压DP

    Fighting for Triangles 题目连接: http://codeforces.com/gym/100015/attachments Description Andy and Ralph ...

  2. codeforces 342D Xenia and Dominoes(状压dp+容斥)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud D. Xenia and Dominoes Xenia likes puzzles ...

  3. Codeforces 375C - Circling Round Treasures(状压 dp+最短路转移)

    题面传送门 注意到这题中宝藏 \(+\) 炸弹个数最多只有 \(8\) 个,故考虑状压,设 \(dp[x][y][S]\) 表示当前坐标为 \((x,y)\),有且仅有 \(S\) 当中的物品被包围在 ...

  4. Codeforces Beta Round #16 E. Fish (状压dp)(概率dp)

    Codeforces Beta Round #16 (Div. 2 Only) E. Fish 题目链接:## 点击打开链接 题意: 有 \(n\) 条鱼,每两条鱼相遇都会有其中一只吃掉对方,现在给你 ...

  5. codeforces gym #101161H - Witcher Potion(状压DP)

    题目链接: http://codeforces.com/gym/101161/attachments 题意: 总共有n瓶药可供选择 每瓶药可以增加$e_i$点体力,和$p_i$点毒性 每分钟消耗1点毒 ...

  6. Codeforces 580D Kefa and Dishes(状压DP)

    题目大概说要吃掉n个食物里m个,吃掉各个食物都会得到一定的满意度,有些食物如果在某些食物之后吃还会增加满意度,问怎么吃满意度最高. dp[S][i]表示已经吃掉的食物集合是S且刚吃的是第i个食物的最大 ...

  7. CodeForces 385 D.Bear and Floodlight 状压DP

    枚举灯的所有可能状态(亮或者不亮)(1<<20)最多可能的情况有1048576种 dp[i]表示 i 状态时灯所能照射到的最远距离(i 的二进制中如果第j位为0,则表示第j个灯不亮,否则就 ...

  8. Codeforces 599E Sandy and Nuts(状压DP)

    题目链接 Sandy and Nuts 题意大概就是给出限制条件求出在该限制条件下树的种数. #include <bits/stdc++.h> using namespace std; # ...

  9. Codeforces Beta Round #8 C. Looking for Order 状压dp

    题目链接: http://codeforces.com/problemset/problem/8/C C. Looking for Order time limit per test:4 second ...

随机推荐

  1. 分享一份软件测试项目实战(web+app+h5+小程序)

    大家好,我是谭叔. 本次,谭叔再度出马,给大家找了一个非常适合练手的软件测试项目,此项目涵盖web端.app端.h5端.小程序端,可以说非常之全面. 缘起 在这之前,谭叔已经推出了九套实战教程. 但是 ...

  2. Dapr-服务调用

    前言 上一篇对Dapr进行了了解,并搭建了Dapr环境.接下来就对Dapr的各个构建块类型的了解.应用实际案例. 一.服务调用: 在许多具有多个需要相互通信的服务的环境中,都会面临着很多问题. 如: ...

  3. WEB安全指南

    说明:本文是Mozilla Web应用部署文档,对运维或者后端开发团队的部署行为进行指导.该部署安全规范内容充实,对于部署有很大意义.同时也涉及到了许多web前端应用安全的基本知识,如CSP, TOK ...

  4. 974.和可被K整除的子数组

    题目 给定一个整数数组 A,返回其中元素之和可被 K 整除的(连续.非空)子数组的数目. 示例: 输入:A = [4,5,0,-2,-3,1], K = 5 输出:7 解释: 有 7 个子数组满足其元 ...

  5. spring mvc 原理(快速理解篇)

    这两张图大家应该都不陌生. 从图上来看就是:一个请求过来,front controller根据具体的请求路径分派到具体的controller,具体的controller处理请求并把处理结果返回给fro ...

  6. (四)php连接apache ,使用php-fpm方式

    上面各篇记录了编译安装lamp的各个部分,下面主要解决php和apache的连接问题.通过 php-fpm 连接. 连接前环境检查: php -v PHP 5.6.30 (cli) (built: O ...

  7. 源码安装的应用 rpm 命令无法查询

    源码安装:一大堆源码文件,需要编译后才能使用(编译需要安装编译器 :yum install gcc) rpm 安装:redhat 官网或其它开源网站编译好发布,已经编译好的安装包,使用 rpm -iv ...

  8. Dubbo的反序列化安全问题-Hessian2

    0 前言 本篇是系列文章的第一篇,主要看看Dubbo使用反序列化协议Hessian2时,存在的安全问题.文章需要RPC.Dubbo.反序列化等前提知识点,推荐先阅读和体验Dubbo以及反序列化漏洞. ...

  9. Java多线程| 01 | 线程概述

    Java多线程| 01 | 线程概述 线程相关概念 进程与线程 进程:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是操作系统进行资源分配与调度的基本单位.可以把进程简单的理解 ...

  10. 在Vs code中使用sftp插件以及连接windows远程sftp协议部署指导(解决vscode的sftp插件中文目录乱码问题)

    一.启动SFtp 二.上手vs code SFTP插件 2.1 初始配置 2.2解决乱码问题 三.SFTP配置 3.1常用配置 3.2示例配置 四.SFTP使用 五.扩展阅读 一.启动SFtp 话说小 ...