- 给定一个长度为 (n) 的序列 (a_{0sim n-1}),表示有 (a_i) 块口味值为 (2^i) 的饼干。
- 你需要选出若干饼干分成 (m) 份。
- 求有多少种不同的 (t) 值,使得存在一种每份饼干口味值之和都为 (t) 的方案。
- 数据组数(le10^3),(1le nle 60),(1le sum a_i imes2^ile10^{18})
动态规划
一个复杂度不够优秀的做法,但毕竟数据范围只有 (60),还是足以通过本题的。
考虑如何唯一的表示一种 (t) 值。
由于小的可以拼成大的,而大的不能拆成小的,因此我们不妨 从大到小枚举,每次能填就填。
然后发现可以划分出若干段,每段中除了最后一个位置以外都是饼干不够分,而最后一个位置则有充足的饼干。
因此设 (f_i) 表示最后一段结尾为(i)的方案数。
转移时在 (0sim i-1) 中枚举 (j) 表示 新一段的开始,为了防止算重,强制第 (j) 位为 (1) 且第 (j+1sim i-1) 位为 (0)。
接着从大到小枚举 (k) 表示 新一段的结尾,记录这一段中能满足之前所有位置饼干都不够分的最小数 (s),维护第 (ksim j) 位的饼干口味值总和 (t)(除以 (2^k),因为不能算入第 (0sim k-1) 位)。
如果 (s>lfloorfrac tm floor),那么这个位置肯定无法作为这一段的结尾,跳过。
否则,如果 (lfloorfrac tm floor<2^{j-k+1}-1),则这一段中的数实际上可以在 (ssim lfloorfrac mt floor) 中任选,因此给 (f_i) 乘上一个系数 (lfloorfrac tm floor-s+1) 转移到 (f_k),然后更新 (s) 为 (lfloorfrac mt floor+1)(因为接着处理之后的位就要求这一位饼干不够分)。
不然,这一位肯定有充足的饼干,这一段中的数可以在 (ssim 2^{j-k+1}-1) 中任选,给 (f_i) 乘上一个系数 (2^{j-k+1}-s) 转移到 (f_k),然后结束对 (k) 的枚举。
代码:(O(T60^3))
#include "biscuits.h"
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define N 60
#define LL long long
using namespace std;
int n;LL f[N+5];LL count_tastiness(LL m,vector<LL> a)
{
RI lim=61-log2(m);memset(f,0,sizeof(f)),a.resize(lim);
RI i,j,k;LL s,t,ans=0;for(f[i=lim]=1;~i;ans+=f[i--]) for(j=i-1;~j;--j)//枚举上一段的结尾和新一段的开头
if(a[j]>=m) f[j]+=f[i];else for(s=1,t=a[j],k=j-1;~k;--k) if(s<<=1,(t<<=1)+=a[k],s<=t/m)//更新s,t;s<=t/m才可能作为一段结尾
if(t/m<(1LL<<j-k+1)-1) f[k]+=f[i]*(t/m-s+1),s=t/m+1;else {f[k]+=f[i]*((1LL<<j-k+1)-s);break;}//根据t/m与2^(j-k+1)-1的大小讨论
return ans;
}