• AGC037 C Numbers on a Circle【思维】


    题目传送门

    题意

    这道题被某大佬改编拿来出成考试题,是长这个样子的:

     

     好的,其实这才是真正的题意:

    给定初始序列和最终序列,每次选择一个数变成自己和相邻2个数的和。问初始序列是否可以变为最终序列,若可以,问最少需要多少次。

    分析

    发现这道题有很多种操作方式,就算是写搜索暴力都不是很好写。

    正难则反,考虑从末状态到初状态,就是一直减去左右两边的数。

    如果中间的数大于两边的数之和,那么中间那个数一定要被操作(设$a,b,c$分别为$i-1,i,i+1$上的$B$值)
    而且在$b>a+c$条件不被破坏时,如果不对$b$操作,那么$a,c$也不会被操作(操作之后为负数,不合法)
    只要$b>a+c$并且$Bi>Ai$ $b$就要一直减去$(a+c)$
    由于是一定要减 是必要的 所以也最小

    $b>a+c$的条件就是在if(...)-1 那个地方判断的 也可以写成if(!step) 就是判断操作次数至少为$1$次
    如果不能操作(操作就成负数)那就不能有解 如果可以操作 下取整操作次数是一定要做的 哪怕只有一次都要做
    做完之后 如果满足了$Ai==Bi$那最好 就ok啦
    但如果不满足 根据step的算法 就是再减一次就变成负数 这个时候$b<a+c$了
    就不一定需要操作 所以继续塞到队列里面等着有朝一日继续操作

    用优先队列呢,也是因为"在$b>a+c$条件不被破坏时,如果不对$b$操作,那么$a,c$也不会被操作(操作之后为负数)"
    如果不先对最大的那个数操作 那么后面也就没有办法操作。

    基本上就是这样了。

    不过还要注意开$long$ $long$(具体次数好像不是很好算,这种不好估计的情况还是都开起比较保险)

    代码

     1 #include<iostream>
     2 #include<string>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<queue>
     6 #include<algorithm>
     7 #include<vector>
     8 using namespace std;
     9 #define N 200005
    10 #define ll long long 
    11 #define fst first
    12 #define snd second
    13 //环:1:2,n n:n-1,1 
    14 int n,a[N],b[N];
    15 ll ans;//记得开ll 
    16 inline int rd()
    17 {
    18     int f=1,x=0;char c=getchar();
    19     while(c<'0'||'9'<c){if(c=='-')f=-f;c=getchar();}
    20     while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    21     return f*x;
    22 }
    23 priority_queue<pair<int,int> >Q;
    24 //pair定义优先队列 先按first 再按second 自动排序 
    25 int main()
    26 {
    27     //freopen("hopeless.in","r",stdin);
    28     //freopen("hopeless.out","w",stdout);
    29     n=rd();
    30     for(int i=1;i<=n;i++)
    31         a[i]=rd();
    32     for(int i=1;i<=n;i++)
    33     {
    34         b[i]=rd();
    35         if(a[i]!=b[i]) Q.push(make_pair(b[i],i));
    36     }
    37     while(!Q.empty())
    38     {
    39         pair<int,int> now=Q.top();Q.pop();
    40         int i=now.snd;
    41         /*int pre=i-1,suf=i+1;
    42         if(pre==0) pre=n;
    43         if(suf==n+1) suf=1;
    44         int step=(b[i]-a[i])/(b[pre]+b[suf]);
    45         */
    46         int pre=(i+n-2)%n+1,suf=i%n+1;
    47         int step=(b[i]-a[i])/(b[pre]+b[suf]);
    48         if(b[i]-b[pre]-b[suf]<a[i])
    49         {
    50             puts("-1");
    51             return 0;
    52         }
    53         ans+=step;
    54         b[i]-=step*(b[pre]+b[suf]);
    55         if(a[i]!=b[i]) Q.push(make_pair(b[i],i));
    56     }
    57     printf("%lld
    ",ans);
    58     return 0;
    59 }
    Code

     

  • 相关阅读:
    System.InvalidOperationException异常的处理!vs15版
    五子棋项目的实现(四)具体的总结
    五子棋项目的实现(三)人机对战类的具体设计
    五子棋项目的实现(二)博弈树算法的描述
    五子棋项目的实现(一)
    java Exception和Error的区别
    java内存分配实例
    expdp与impdp
    SQL*PLUS下使用AUTOTRACE、sql顾问、实时sql监控
    Linux下如何将数据库脚本文件从sh格式变为sql格式
  • 原文地址:https://www.cnblogs.com/lyttt/p/11774949.html
Copyright © 2020-2023  润新知