AGC037 C Numbers on a Circle思维

Posted lyttt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

 

 

以上是关于AGC037 C Numbers on a Circle思维的主要内容,如果未能解决你的问题,请参考以下文章

agc037_f Counting of Subarrays

「 solution set」 AGC037

[AGC011E] Increasing Numbers [数学]

[agc011e]increasing numbers

AGC011-E Increasing Numbers

[AGC 011 E]Increasing Numbers