CF 1225G To Make 1(转化,状压DP,bitset)

mac2026-01-20  4

直接按照题目的过程模拟是 O ( n ! ) O(n!) O(n!)的, D P DP DP O ( 3 n Σ a i ) O(3^n\Sigma a_i) O(3nΣai)的。

考虑将题目的过程规约到另一个问题。

寻找一组解 b i b_i bi使得 1 = ∑ i a i k − b i 1 = \sum_{i}a_ik^{-b_i} 1=iaikbi

首先显然任意的一个可以得出1的合并过程都可以推出一组解 b i b_i bi

证明:一定可以通过 b i b_i bi构造出一组解。

先证明一个引理:当数字的数量 n > 1 n>1 n>1时一定有两个不相等的 j , k j,k j,k满足 b k = b j = ( int  B = max ⁡ i b i ) b_k = b_j= (\text{int} \ B = \max_i{b_i}) bk=bj=(int B=maxibi)应该懂我的B什么意思吧

引理的证明: 1 = ∑ i a i k − b i − > k B = ∑ i a i k B − b i 1 = \sum_{i}a_ik^{-b_i} -> k^B = \sum_{i}a_ik^{B-b_i} 1=iaikbi>kB=iaikBbi

这个等式两边的任意一项都是整数。

而左边被 k k k整除,右边的所有的 b i < B b_i < B bi<B a i k B − b i a_ik^{B-b_i} aikBbi也被 k k k整除

所以右边的所有的 b i = B b_i=B bi=B a i k B − b i a_ik^{B-b_i} aikBbi的和一定被 k k k整除。

也就是说所有的 b i = B b_i=B bi=B a i a_i ai的和被 k k k整除。

通过阅读英文版的输入格式我们可以发现不存在 k ∣ a i k|a_i kai

所以 b i = B b_i=B bi=B a i a_i ai至少有两个。

所以对于一组 b i b_i bi,我们取出 b k = b j = B b_k =b_j = B bk=bj=B

a k a_k ak a j a_j aj合并得到 a ′ a' a

发现合并后依然满足不存在 k ∣ a ′ k|a' ka

并且我们可以推出来合并出来的 a ′ a' a它应该对应的 b ′ b' b,把它们加入,就得到了一个规模为 n − 1 n-1 n1的子问题,得到了一个 ∣ b ∣ = n − 1 |b|=n-1 b=n1 b i b_i bi

而当 n = 1 n=1 n=1的时候我们就得到了 1 1 1

可以设计 d p s , u = 1 dp_{s,u}=1 dps,u=1表示加入了 s s s集合内的所有 a i a_i ai后可以得到 u = ∑ i a i k − b i u = \sum_{i}a_ik^{-b_i} u=iaikbi

可以简单转移,但是会 T L E TLE TLE,用 b i t s e t bitset bitset优化状态存储和转移即可 A C AC AC.

A C   C o d e \rm AC \ Code AC Code

#include<bits/stdc++.h> #define maxn 2005 #define pii pair<int,int> #define mp make_pair using namespace std; int n,k,a[16],lg[1<<16],N,sum; bitset<maxn> dp[1<<16]; int d[16]; priority_queue<pii >q; void dfs(int sta,int s){ if(!sta) return; for(;s*k<=sum && dp[sta][s*k];s*=k) for(int t=sta;t;t-=t&-t) d[lg[t&-t]]++; for(int t=sta;t;t-=t&-t) if(s>=a[lg[t&-t]] && dp[sta-(t&-t)][s-a[lg[t&-t]]]){ dfs(sta-(t&-t),s-a[lg[t&-t]]); return; } } int main(){ scanf("%d%d",&n,&k);N=1<<n; for(int i=0;i<n;i++) scanf("%d",&a[i]),lg[1<<i]=i,sum+=a[i]; dp[0][0] = 1; for(int i=1;i<N;i++){ for(int t=i;t;t-=t&-t){ int v=t&-t , u = lg[v]; dp[i] |= (dp[i-v]<<a[u]); } for(int j=sum/k;j>=1;j--) if(dp[i][j*k]) dp[i][j] = 1; } if(!dp[N-1][1]) puts("NO"); else{ puts("YES"); dfs(N-1,1); for(int i=0;i<n;i++) q.push(mp(d[i],a[i])); for(;q.size() > 1;){ pii u = q.top();q.pop(); pii v = q.top();q.pop(); printf("%d %d\n",u.second,v.second); u.second += v.second; for(;u.second % k == 0;u.second /= k) u.first --; q.push(u); } } }
最新回复(0)