zoukankan      html  css  js  c++  java
  • AT5160[AGC037C]Numbers on a Circle【贪心,堆】

    正题

    题目链接:https://www.luogu.com.cn/problem/AT5160


    题目大意

    给出两个长度为\(n\)的环序列\(a\)\(b\),每次你可以让\(a\)中的一个数变为它和相邻两个的和。

    求最少的步数将\(a\)变为\(b\)

    \(1\leq n\leq 10^5,1\leq a_i,b_i\leq 10^9\)


    解题思路

    被蓝题D烂了。

    考虑反过来做,每次操作为\(B_i=B_i-B_{i-1}-B_{i+1}\)

    然后考虑怎么搞这个东西,注意到\(B_i\)不能够减到负数所以同理也不能减到小于\(A_i\),考虑如果对于一个\(B_i\geq B_{i-1}+B_{i+1}\)那么此时位置\(i-1\)\(i+1\)显然都是不能动的,那么我们动\(B_{i}\)就一定是最优的。

    还有如果\(B_i=A_i\)时那么\(B_i\)就是不可以再操作的了。

    具体地我们每次找到最大的可操作的\(B_i\),然后把它减到不能再减即可,然后过程中判断是否无解即可。

    由于每次至少减半所以每个数应该会操作最多\(log\)次。

    时间复杂度:\(O(n\log n\log w)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define ll long long
    #define mp(x,y) make_pair(x,y)
    using namespace std;
    const ll N=2e5+10;
    ll n,a[N],b[N],ans;
    priority_queue<pair<int,int> > q;
    ll pl(ll x){return (x==1)?n:(x-1);}
    ll pr(ll x){return (x==n)?1:(x+1);}
    signed main()
    {
    	scanf("%lld",&n);
    	for(ll i=1;i<=n;i++)
    		scanf("%lld",&a[i]);
    	for(ll i=1;i<=n;i++){
    		scanf("%lld",&b[i]),q.push(mp(b[i],i));
    		if(a[i]>b[i])return puts("-1")&0;
    	}
    	while(!q.empty()){
    		ll x=q.top().second;q.pop();
    		if(b[x]==a[x])continue;
    		ll d=b[pl(x)]+b[pr(x)];
    		if(b[x]-d<a[x])break;
    		ans+=(b[x]-a[x])/d;
    		b[x]-=(b[x]-a[x])/d*d;
    		if(b[x]!=a[x])q.push(mp(b[x],x));
    	}
    	if(q.size())puts("-1");
    	else printf("%lld\n",ans);
    	return 0;
    }
    
  • 相关阅读:
    利用URL protocol在网页打开本地exe
    [Leetcode]50. Pow(x, n)
    【转载】初识google test
    MySQL主从配置【转载】
    MySQL源码安装(centos)
    MySQL数据库MyISAM和InnoDB存储引擎的比较【转载】
    MySQL 事务
    MySQL 对于千万级的大表要怎么优化
    MySQL性能优化的最佳21条经验【转载】
    mysql日志详细解析【转载】
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15471734.html
Copyright © 2011-2022 走看看