ARC112 F - Die Siedler 题解
题目链接:F - Die Siedler
题目大意:给定一个序列 \(a_1,a_2,\dots,a_n\),有 \(m\) 个长度为 \(n\) 的序列 \(s_{1,1},s_{1,2},\dots,s_{1,n},s_{2,1},s_{2,2},\dots,s_{2,n},\dots,s_{m,1},s_{m,2},\dots,s_{m,n}\),你可以将这 \(m\) 个序列中的每一个给 \(a\) 加任意多次,两个序列的加法定义为 \(a+b=\{a_1+b_1,a_2+b_2,\dots,a_n+b_n\}\)。
在加完之后,对 \(a\) 作如下变换:若 \(a_i\ge 2\times i\),则令 \(a_i-=2\times i,a_{i\bmod n+1}+=1\),求 \(\sum_{i=1}^n a_i\) 的最小值。
题解:首先我们能够发现我们可以把所有的数堆在 \(a_1\) 上,具体操作就是将 \(a_1\) 变为 \(\sum_{i=1}^n a_i\times 2^{i-1}\times (i-1)!\),将 \(a_2,a_3,\dots,a_n\) 变为 \(0\),将 \(a_1\) 定义为序列的权值。
令 \(a\) 序列的权值为 \(C\),序列 \(\{s_i\}\) 的权值为 \(s_i\)。
那么假设我们最后的序列的权值是 \(C^{\prime}\),那么可以得到 \(C^{\prime}=C+x_1\cdot s_1+x_2\cdot s_2+\cdots x_m\cdot s_m\)。
但是我们发现如果按照题目意思一次操作 \(1,2,\dots,n\) 可以使 \(a_1\) 减去 \(2^n n!-1\),所以 \(C^{\prime}=C+x_1\cdot s_1+x_2\cdot s_2+\cdots x_m\cdot s_m-y\cdot (2^n n!-1)\)。
由裴蜀定理可得 \(\gcd(s_1,s_2,\dots,s_m,2^n n!-1)|(C^{\prime}-C)\)。
那么令 \(d=\gcd(s_1,s_2,\dots,s_m,2^n n!-1)\)。
接下来我们有两种做法:
- 直接枚举 \(C\bmod d+kd\) 中的 \(k\),因为 \(d\) 是 \(2^n n!-1\) 的因数,所以我们只需要枚举到 \(2^n n!-1\) 就可以了,时间复杂度 \(O(\frac{2^n n!}{d})\)。
- 考虑同余最短路,\(i\) 向 \(i+2^{j-1}(j-1)!\) 连长度为 \(1\) 的边,最后输出 \(dis_{C\bmod d}\),时间复杂度 \(O(nd)\)。
所以时间复杂度为 \(O(\min(nd,\frac{2^n n!}{d}))\),打表发现可以过。
代码:
#include <cstdio>
#include <algorithm>
typedef long long ll;
ll gcd(ll a,ll b){
if(b==0){
return a;
}
return gcd(b,a%b);
}
const int Maxn=16;
const int Maxm=50;
const int Maxd=1500000;
const int Inf_int=0x3f3f3f3f;
int n,m;
ll pow_fac[Maxn+5];
ll C;
ll read_val(){
ll ans=0;
for(int i=0;i<n;i++){
int val;
scanf("%d",&val);
ans+=val*pow_fac[i];
}
return ans;
}
int find_ans(ll s){
int ans=0;
for(int i=1;i<=n;i++){
ans+=s%(2*i);
s/=2*i;
}
return ans;
}
int dis[Maxd+5];
int qu[Maxd+5],qu_f,qu_t;
int main(){
pow_fac[0]=1;
for(int i=1;i<=Maxn;i++){
pow_fac[i]=pow_fac[i-1]*2*i;
}
scanf("%d%d",&n,&m);
ll d=pow_fac[n]-1;
C=read_val();
for(int i=1;i<=m;i++){
d=gcd(d,read_val());
}
if(pow_fac[n]/d<d){
int ans=Inf_int;
for(ll i=(C%d==0?d:C%d);i<pow_fac[n];i+=d){
ans=std::min(ans,find_ans(i));
}
printf("%d\n",ans);
}
else{
qu_f=1,qu_t=0;
for(int i=0;i<n;i++){
int u=pow_fac[i]%d;
if(dis[u]==0){
dis[u]=1;
qu[++qu_t]=u;
}
}
int T=C%d;
while(qu_f<=qu_t&&dis[T]==0){
int u=qu[qu_f++];
for(int i=0;i<n;i++){
int v=(u+pow_fac[i])%d;
if(dis[v]==0){
dis[v]=dis[u]+1;
qu[++qu_t]=v;
}
}
}
printf("%d\n",dis[T]);
}
return 0;
}
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。