[atARC112F]Die Siedler
1和2操作是独立的,换言之一定可以先执行1操作选择包裹,再执行2操作使得$0\le c_{i}<2i$
对于$c_{i}$,将其看作一个进制转换,并以$c_{i}$为从低到高的第$i$位,系数即为$2^{i-1}(i-1)!$
将其乘权累加,即令$c_{0}=\sum_{i=1}^{n}2^{i-1}(i-1)!c_{i}$,考虑2操作对$c_{0}$的影响:
1.对于$i$($1\le i<n$)的操作,显然不会改变$c_{0}$
2.对于$n$的操作,即将$c_{0}$减去$2^{n}n!-1$(以下记作$N$)
根据最终$0\le c_{i}<2i$,代入即得到最终的$c'_{0}$满足
$$
c'_{0}\le \sum_{i=1}^{n}(2i-1)2^{i-1}(i-1)!=\sum_{i=1}^{n}2^{i}i!-\sum_{i=1}^{n}2^{i-1}(i-1)!=N
$$
1.对于$c_{0}\not\equiv 0(mod\ N)$的情况,$c'_{0}$一定是$c_{0}$对$N$取模的结果
2.对于$c_{0}\equiv 0(mod\ N)$的特殊情况下,则$c'_{0}=0或N$,由于初始以及任意一次操作后都会有$\sum_{i=1}^{n}c_{i}>0$,即$c'_{0}\ne 0$,因此$c'_{0}=N$
进一步的,确定最终的$1\le c'_{0}\le N$后,根据$0\le c_{i}<2i$,我们也可以从高到低依次确定$c_{i}$,那么也就是说我们仅关心于最终能产生哪些$c'_{0}$
更具体的,令$c_{0}=\sum_{i=1}^{n}2^{i-1}(i-1)!c_{i}$,$s_{i}=\sum_{j=1}^{n}2^{j-1}(j-1)!s_{i,j}$,观察式子可以发现每一项对应相加即为整体相加,因此取第$i$个包裹即令$c_{0}+=s_{i}$(模$N$意义下相加)
每一次都是加上$s_{i}$或减去$N$(模$N$),根据扩欧,有$c'_{0}\equiv c_{0}(mod\ \gcd(N,s_{1},s_{2},...,s_{n}))$,同时可以构造出一组整数解(不保证$s_{i}$系数非负且$N$系数非正),通过这组解,不断令$s_{i}$的系数加上$N$、$N$的系数减去$s_{i}$使其满足上面的两个条件,因此都是可以的
令$d=\gcd(N,s_{1},s_{2},...,s_{n})$,来考虑两种做法:
1.暴力枚举所有$c'_{0}$(要求$1\le c'_{0}\le N$)并构造出对应$c_{i}$,然后求出答案,这一做法复杂度为$o(\frac{nN}{d})$
2.先来构造最终的$c_{i}$,即要使得$\sum_{i=1}^{n}2^{i-1}(i-1)!c_{i}\equiv c_{0}(mod\ d)$
这个可以看作从$c_{i}=\{0,0,...,0\}$开始,将其中某一个$c_{i}$加1,移动到另一个点,由于我们仅关心于其模$d$的余数,因此可以看作一个大小为$d$的图,bfs即可,时间复杂度为$o(nd)$
(当$c_{0}\equiv 0(mod\ d)$时需要特判,因为不能令$c_{i}=\{0,0,...,0\}$)
由此,我们得到了一个$o(n\sqrt{N})$的做法,但复杂度似乎还不能接受
注意到$N=2^{n}n!-1$,$d$必然是其因子,而由于$N$形式的特殊性,打表可得
$$
\max_{2\le n\le 16,N=2^{n}n!-1,d|N}n\min(\frac{N}{d},d)\le 14577924
$$
(最大值是在$n=12$时取到,$d=1214827$)
上面这个式子即复杂度,那么就可以通过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define oo 0x3f3f3f3f 5 queue<int>q; 6 vector<int>dis; 7 int n,m,x,ans; 8 ll N,d,c,val[21]; 9 ll gcd(ll x,ll y){ 10 if (!y)return x; 11 return gcd(y,x%y); 12 } 13 int main(){ 14 scanf("%d%d",&n,&m); 15 val[1]=1; 16 for(int i=2;i<=n;i++)val[i]=2*(i-1)*val[i-1]; 17 d=N=2*n*val[n]-1; 18 for(int i=1;i<=n;i++){ 19 scanf("%d",&x); 20 c+=x*val[i]; 21 ans+=x; 22 } 23 for(int i=1;i<=m;i++){ 24 ll s=0; 25 for(int j=1;j<=n;j++){ 26 scanf("%d",&x); 27 s+=x*val[j]; 28 } 29 d=gcd(d,s); 30 } 31 if (d>N/d){ 32 for(ll i=c%d;i<=N;i+=d){ 33 if (!i)continue; 34 ll k=i; 35 int s=0; 36 for(int j=n;j;j--){ 37 s+=k/val[j]; 38 k%=val[j]; 39 } 40 ans=min(ans,s); 41 } 42 printf("%d",ans); 43 return 0; 44 } 45 for(int i=0;i<d;i++)dis.push_back(oo); 46 dis[0]=0; 47 q.push(0); 48 while (!q.empty()){ 49 int k=q.front(); 50 q.pop(); 51 for(int i=1;i<=n;i++) 52 if (dis[(k+val[i])%d]==oo){ 53 dis[(k+val[i])%d]=dis[k]+1; 54 q.push((k+val[i])%d); 55 } 56 } 57 if (c%d)printf("%d",dis[c%d]); 58 else{ 59 for(int i=1;i<=n;i++)ans=min(ans,dis[(N-val[i])%d]+1); 60 printf("%d",ans); 61 } 62 }