zoukankan      html  css  js  c++  java
  • 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)\)

    接下来我们有两种做法:

    1. 直接枚举 \(C\bmod d+kd\) 中的 \(k\),因为 \(d\)\(2^n n!-1\) 的因数,所以我们只需要枚举到 \(2^n n!-1\) 就可以了,时间复杂度 \(O(\frac{2^n n!}{d})\)
    2. 考虑同余最短路,\(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;
    }
    
  • 相关阅读:
    设计模式学习
    rabbitMQ topic实现广播
    rabbitMQ direct实现广播
    rabbitMQ fanout 实现广播
    rabbitMQ 生产者消费者
    python select 实现IO异步
    python gevent 爬虫
    python gevent socket
    python 协程
    python 进程池
  • 原文地址:https://www.cnblogs.com/withhope/p/15538590.html
Copyright © 2011-2022 走看看