题目描述

给定 \(n\) 个数和 \(a,b\) 每次可以选择一段区间 \(+a,-a,+b ,或 -b\),问最少操作几次能把它们都变成 \(0\)。如果无解请输出 \(-1\)。

样例输入

5 2 3
1 2 1 1 -1
5

分析

对于区间修改是很麻烦的,为了简化复杂度,这里可以将数组转化为差分数组以降低难度,对于每一个数,我们实际上都可以找

出一个方程 \(0+ax+by=c\) 这里的 \(c\) 实际上就是原序列数,看着是不是很眼熟,没错,就是扩展欧几里得定理,这里的\(x,y\)

指的是对 \(a,b\) 进行的操作,一次\(+a,-a\) , \(+b,-b\),互相抵消,所以肯定不是最优解,可以不考虑,那会不会出现一个数两边

的区间减去一个数,但这个数不用减的情况呢,因为这里使用的是差分数组进行的操作,进行的是单点修改,在每一个点的修改

对区间的影响是与之前点的修改相关的,每一个点的加减组合起来就完成了对于所有区间的遍历,所以这种情况也会被考虑在内

因为一次对一个数的部分操作 \(x\) , \(y\) 是对其他数操作时对这个数的影响,所以一次操作被算了两遍,所以最后答案实际上是

\(\frac{\sum(x+y)}{2}\) ,这里要先处理出方程等于 \(gcd(a,b)\) 的两特解,即为

  • 1 \(x\)最小正整数解,\(y\) 最大负整数解

  • 2 \(x\)最大负整数解,\(y\) 最小正整数解

这里是因为要保证代价最小,接着根据裴蜀定理,让序列里的数膜上 \(gcd(a,b)\) 判断是否有解,然后我们要不断去找\(x,y\)的最小

加和最小解,因为\(x,y\) 之间具有方程关系,所以只需要考虑 \(x\) 的操作,再进行判断就可以了,这里可以用一个小根堆去维护,

每次取出最小代价操作,这里需要注意一个点,因为操作 \(a,b\) 时有加有减,所以\(x,y\) 可能出现负数,在这里先假设对 \(x\) 的

操作更多且为正,然后根据通解公式$$x=x_0+k*\frac{b}{gcd(a,b)}$$,

\[y=y_0+k*\frac{a}{gcd(a,b)}
\]

每次让取出的 \(x\) 减去 \(\frac{b}{gcd(a,b)}\) ,对应的 \(y\) 加上 \(\frac{a}{gcd(a,b)}\),不断更新即可,这里可以提前求一下 \(x\) 操作数的和,最多更新次数就是

\(\frac{\sum x}{b_0}\) , \((b_0=\frac{b}{gcd(a,b)})\) 因为已经保证了 \(cnt_x\) \(>\) \(cnt_y\) ,所以对于所有的 \(y\) 一定进行更新了,最后把所有操作的 \(x,y\) 加起来再

除二即为答案

solution

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=(1<<17)+10; long long n,m,sum[maxn],a,b,X[maxn],Y[maxn]; priority_queue <pair<int,int> >q; int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
int res=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-y*(a/b);
return res;
} bool pd(int x,int y,int xx,int yy)
{
return abs(x)+abs(y)<abs(xx)+abs(yy);
} signed main()
{
scanf("%lld%lld%lld",&n,&a,&b);
for(int i=1;i<=n;i++)
scanf("%lld",&sum[i]);
for(int i=n+1;i>=1;i--)
{
sum[i]=sum[i]-sum[i-1];//差分,要多处理一个数0,对答案无影响
}
int x=0,y=0;
int d=exgcd(a,b,x,y);
a/=d,b/=d;
for(int xx,yy,i=1;i<=n+1;i++)
{
int c=sum[i]/d;
if(sum[i]%d!=0){puts("-1");return 0;}
xx=X[i]=(x*c%b+b)%b;//x最小正解
yy=Y[i]=(c-xx*a)/b;//y最大负解
xx-=b,yy+=a;
if(pd(xx,yy,X[i],Y[i]))X[i]=xx,Y[i]=yy;
yy=(y*c%a+a)%a;//y最小正解
xx=(c-yy*b)/a;//x最小负解
if(pd(xx,yy,X[i],Y[i]))X[i]=xx,Y[i]=yy;
yy-=a,xx+=b;
if(pd(xx,yy,X[i],Y[i]))X[i]=xx,Y[i]=yy;
}
int temp=0;
for(int i=1;i<=n+1;i++) temp+=X[i];
temp/=b;
if(temp<0)temp=-temp,swap(a,b),swap(X,Y);//保证X为正
for(int i=1;i<=n+1;i++) q.push(make_pair(-(abs(X[i]-b)+abs(Y[i]+a)-abs(X[i])-abs(Y[i])),i));
while(temp--)
{
int u=q.top().second;
q.pop();
X[u]-=b,Y[u]+=a;
q.push(make_pair(-(abs(X[u]-b)+abs(Y[u]+a)-abs(X[u])-abs(Y[u])),u));
}
int ans=0;
for(int i=1;i<=n+1;i++)ans+=abs(X[i])+abs(Y[i]);
printf("%lld",ans>>1); return 0;
}

洛谷P3543 [POI2012] WYR-Leveling Ground的更多相关文章

  1. 洛谷 P3539 [POI2012]ROZ-Fibonacci Representation 解题报告

    P3539 [POI2012]ROZ-Fibonacci Representation 题意:给一个数,问最少可以用几个斐波那契数加加减减凑出来 多组数据10 数据范围1e17 第一次瞬间yy出做法, ...

  2. 洛谷P3533 [POI2012]RAN-Rendezvous

    P3533 [POI2012]RAN-Rendezvous 题目描述 Byteasar is a ranger who works in the Arrow Cave - a famous rende ...

  3. BZOJ2801/洛谷P3544 [POI2012]BEZ-Minimalist Security(题目性质发掘+图的遍历+解不等式组)

    题面戳这 化下题面给的式子: \(z_u+z_v=p_u+p_v-b_{u,v}\) 发现\(p_u+p_v-b_{u,v}\)是确定的,所以只要确定了一个点\(i\)的权值\(x_i\),和它在同一 ...

  4. 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash]

    题目传送门 A Horrible Poem 题目描述 Bytie boy has to learn a fragment of a certain poem by heart. The poem, f ...

  5. 洛谷P3539 [POI2012] ROZ-Fibonacci Representation

    题目传送门 转载自:five20,转载请注明出处 本来看到这题,蒟蒻是真心没有把握的,还是five20大佬巨orz 首先由于斐波拉契数的前两项是1,1 ,所以易得对于任何整数必能写成多个斐波拉契数加减 ...

  6. 洛谷P3537 [POI2012]SZA-Cloakroom(背包)

    传送门 蠢了……还以为背包只能用来维护方案数呢……没想到背包这么神奇…… 我们用$dp[i]$表示当$c$的和为$i$时,所有的方案中使得最小的$b$最大时最小的$b$是多少 然后把所有的点按照$a$ ...

  7. 洛谷P3531 [POI2012]LIT-Letters

    题目描述 Little Johnny has a very long surname. Yet he is not the only such person in his milieu. As it ...

  8. 洛谷P3534 [POI2012] STU

    题目 二分好题 首先用二分找最小的绝对值差,对于每个a[i]都两个方向扫一遍,先都改成差满足的形式,然后再找a[k]等于0的情况,发现如果a[k]要变成0,则从他到左右两个方向上必会有两个连续的区间也 ...

  9. 【洛谷3546_BZOJ2803】[POI2012]PRE-Prefixuffix(String Hash)

    Problem: 洛谷3546 Analysis: I gave up and saw other's solution when I had nearly thought of the method ...

  10. [洛谷3457][POI2007]POW-The Flood

    洛谷题目链接:[POI2007]POW-The Flood 题意翻译 Description 你手头有一张该市的地图.这张地图是边长为 m∗n 的矩形,被划分为m∗n个1∗1的小正方形.对于每个小正方 ...

随机推荐

  1. 记一次 .NET某管理局检测系统 内存暴涨分析

    一:背景 1. 讲故事 前些天有位朋友微信找到我,说他们的WPF程序有内存泄漏的情况,让我帮忙看下怎么回事?并且dump也抓到了,网上关于程序内存泄漏,内存暴涨的文章不计其数,看样子这个dump不是很 ...

  2. Python 内置数据类型详解

    内置数据类型 在编程中,数据类型是一个重要的概念. 变量可以存储不同类型的数据,不同类型可以执行不同的操作. Python默认内置了以下这些数据类型,分为以下几类: 文本类型:str 数值类型:int ...

  3. MogDB-opengauss中的聚集与分组操作

    MogDB/opengauss 中的聚集与分组操作 COUNT:对结果集中的元组数量进行计数,如果是 COUNT(*),那么会统计所有元组(包括 NULL 值)的数量,如果是 COUNT(colnam ...

  4. HarmonyOS 3百机升级计划,来了!

    HarmonyOS 3规模升级来了! 为大家奉上百余款机型升级计划! 你的手机什么时候可以升级? 赶快下滑查看!

  5. 重新整理数据结构与算法(c#)——算法套路普利姆算法[二十九]

    前言 看一个题目: 这个问题就是求最小生成树,是图转换为树的一种方式. 最小生成树概念: 最小生成树简称MST. 1.n个顶点,一定有n-1条边 2.包含全部顶点. 3.图转换为最小生成树,权重之和最 ...

  6. Spring JDBCTemplet通用RowMapper帮助类

    1 import java.lang.reflect.Method; 2 import java.math.BigDecimal; 3 import java.math.BigInteger; 4 i ...

  7. Springmvc来做甘特图的显示控制。

    springmvc没有Springboot好用:所以就用了ajax通信来获取数据,这其中有不少坑,我来带大家踩一踩. 1.在控制层中,接口不能直接返回Json格式. 我的解决方法可以使通过map,或者 ...

  8. oracle表名、字段名等对象的命名长度限制(报错:ORA-00972: 标识符过长)

    oracle表名.字段名等对象的命名长度限制(报错:ORA-00972: 标识符过长) 简单来说,出现了ORA-00972: 标识符过长的错误 找来找去发现是自己的中间表名太长导致的 Oracle数据 ...

  9. 05_理解MVVM模型

    总结: MVVM模型:         1.M:模型(Model):data中是的数据         2.V:视图(View):模板代码         3.VM:视图模型(ViewModel):V ...

  10. 力扣504(java)-七进制数(简单)

    题目: 给定一个整数 num,将其转化为 7 进制,并以字符串形式输出. 示例 1: 输入: num = 100输出: "202"示例 2: 输入: num = -7输出: &qu ...