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. 自动化运维利器Ansible要点汇总

    由于大部分互联网公司服务器环境复杂,线上线下环境.测试正式环境.分区环境.客户项目环境等造成每个应用都要重新部署,而且服务器数量少则几十台,多则千台,若手工一台台部署效率低下,且容易出错,不利后期运维 ...

  2. 脚本注入3(blind)

    布尔盲注适用于任何情况回显都不变的情况. (由此,可以看出,回显啥的其实都不重要,最重要的是判断注入点.只要找到注入点了,其他的都是浮云.) 在操作上,时间盲注还稍微简单一点:它不需要像布尔盲注那样, ...

  3. 【c++ Prime 学习笔记】第10章 泛型算法

    标准库未给容器添加大量功能,而是提供一组独立于容器的泛型算法 算法:它们实现了一些经典算法的公共接口 泛型:它们可用于不同类型的容器和不同类型的元素 利用这些算法可实现容器基本操作很难做到的事,例如查 ...

  4. Java中的函数式编程(七)流Stream的Map-Reduce操作

    写在前面 Stream 的 Map-Reduce 操作是Java 函数式编程的精华所在,同时也是最为复杂的部分.但一旦你啃下了这块硬骨头,那你就真正熟悉Java的函数式编程了. 如果你有大数据的编程经 ...

  5. 第六次Alpha Scrum Meeting

    本次会议为Alpha阶段第六次Scrum Meeting会议 会议概要 会议时间:2021年5月2日 会议地点:线上会议 会议时长:20min 会议内容简介:本次会议主要由每个人展示自己目前完成的工作 ...

  6. Noip模拟78 2021.10.16

    这次时间分配还是非常合理的,但可惜的是$T4$没开$\textit{long long}$挂了$20$ 但是$Arbiter$上赏了蒟蒻$20$分,就非常不错~~~ T1 F 直接拿暴力水就可以过,数 ...

  7. DMA实现采样数据的直接搬运存储

    尝试了下STM32的ADC采样,并利用DMA实现采样数据的直接搬运存储,这样就不用CPU去参与操作了. 找了不少例子参考,ADC和DMA的设置了解了个大概,并直接利用开发板来做一些实验来验证相关的操作 ...

  8. 使用spire.doc导出支持编辑Latex公式的标准格式word

    背景 之前有的教辅标注需求,在导出题库的时候希望顺便导出可以查看word,方便线下预览成品效果,因为只是用来预览并且为了沿用前端的样式,当时方案就是直接生成html,写个word的文件头,这样就可以用 ...

  9. 微服务(五)nacos配置管理

    1 统一配置管理 1.1 nacos中添加配置文件 注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要.基本不会变更的一些配置还是保存在微服务本地比较好. 1.2 从微服务拉取配置 微 ...

  10. 同人逼死官方系列!基于sddc 协议的SDK框架 sddc_sdk_lib 解析

    基于sddc 协议的SDK框架 sddc_sdk_lib 解析 之前在移植 libsddc 库的时候感觉官方 demo 太低效了( ̄. ̄),复制粘贴代码好累,而且写出一个BUG,其他复制的代码整个就裂 ...