「EZEC-10」Equalization 题解
定义
下文中 “A 状态” 表示满足所有数之和为
求最少操作次数
对于静态区间加,我们很容易想到对数列的差分数组进行操作。
令
那么可将每次操作转化为:
换句话来说,就是每次你可以进行如下两种操作的其中一种:
-
任选两数
p,q ,d_p:=q 。 -
任选三数
p,q,r ,d_p:=d_p+r,d_q:=d_q-r 。
而根据题目,我们要将
不难发现,若每次都进行第一种操作,次数最多为
观察可得,当
这样,我们的目标就是将
考虑状压。
令
对所有 A 状态
我们对所有
答案即为
时间复杂度为
求方案数
我们只需计算本质不同的方案数,最后乘上最少操作次数的阶乘即可。
先考虑 A 状态。
令
令
对于 A 状态
在
如此重复进行下去,最终所有数均会变为
此时,本质不同的方案数即为
根据 prufer 序列可推得,方案数为
故我们对所有 A 状态
在更新
我们对所有
而这样转移可能会重复计算。
故考虑只枚举不包含任何 A 子集的
当然,每枚举一个
这样我们就成功避免了重复计算的问题。
再考虑 B 状态。
令
不难发现,B 状态中所有数之和与
故将 B 状态再加入
沿用处理 A 状态的思路,而注意,当选中的
故在进行计算时,可以考虑将
根据 prufer 序列可推得,
最后枚举所有能达到最少操作次数的状态。
易得满足条件的状态
将所有状态的贡献相加求和,再乘上最少操作次数的阶乘即为最终答案。
注意特判
时间复杂度仍为
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,cnt,ans1,ans2,a[18],d[18],c[18],fact[18],power[18],f[1 << 17],g[1 << 17],v[1 << 17],val[1 << 17],bit[1 << 17],mod = 1e9 + 7;
inline ll read(){
ll s = 0,w = 1;
char ch = getchar();
while (ch < '0'|| ch > '9'){ if (ch == '-') w = -1; ch = getchar();}
while (ch >= '0'&& ch <= '9') s = (s << 1) + (s << 3) + (ch ^ 48),ch = getchar();
return s * w;
}
ll qp(ll x,ll y){
ll a = 1,b = x;
while (y){
if (y & 1) a = a * b % mod;
b = b * b % mod,y >>= 1;
}
return a;
}
int main(){
n = read();
for (ll i = 0;i < n;i += 1) a[i] = read();
n -= 1;
for (ll i = 0;i < n;i += 1) d[i] = a[i + 1] - a[i];
c[0] = fact[0] = power[1] = 1;
for (ll i = 1;i <= n;i += 1) fact[i] = fact[i - 1] * i % mod;
for (ll i = 2;i <= n;i += 1) power[i] = qp(i,i - 2);
for (ll i = 1;i <= n + 1;i += 1) c[i] = 2 * qp(i + 2,i - 1) % mod;
for (ll i = 1;i < (1 << n);i += 1){
ll sum = 0;
for (ll j = 0;j < n;j += 1) if (i & (1 << j)) sum += d[j],bit[i] += 1;
if (!sum) f[i] = 1,g[i] = power[bit[i]];
}
for (ll i = 1;i < (1 << n);i += 1) if (f[i]){
bool fl = 1;
for (ll j = (i - 1) & i;j;j = (j - 1) & i) if (f[j]){fl = 0; break;}
val[i] = fl;
}
for (ll i = 1;i < (1 << n);i += 1) if (f[i]){
for (ll j = i;j;j = (j - 1) & i) v[j] = 0;
for (ll j = (i - 1) & i;j;j = (j - 1) & i) if (val[j] && !v[j]){
if (f[j] + f[i ^ j] > f[i]) f[i] = f[j] + f[i ^ j],g[i] = g[j] * g[i ^ j] % mod;
else if (f[j] + f[i ^ j] == f[i]) g[i] = (g[i] + g[j] * g[i ^ j] % mod) % mod;
for (ll k = (i ^ j);k;k = (k - 1) & (i ^ j)) v[k] = 1;
}
}
ans1 = n - *max_element(f,f + (1 << n));
if (ans1 == n){cout<<n<<endl<<c[n] * fact[ans1] % mod; return 0;}
for (ll i = 0;i < (1 << n);i += 1) if (f[i] == n - ans1) ans2 = (ans2 + g[i] * c[n - bit[i]] % mod) % mod;
cout<<ans1<<endl<<ans2 * fact[ans1] % mod;
return 0;
}