P1667 数列
题目描述
给定一个长度是n的数列A,我们称一个数列是完美的,当且仅当对于其任意连续子序列的和都是正的。现在你有一个操作可以改变数列,选择一个区间[X,Y]满足Ax +Ax+1 +…+ AY<0,1<X<=Y<n,令S=Ax +Ax+1 +…+ AY,对于Ax-1和AY+1分别加上S,Ax和AY分别减去S(如果X=Y就减两次)。问最少几次这样的操作使得最终数列是完美的。
输入输出格式
输入格式:
第一行一个数n,以下n个数。
【数据规模】
对于20%的数据,满足1≤N≤5;
对于100%的数据,满足1≤N≤10^5; 1≤|A[i]|≤2^31-1。
输出格式:
一个数表示最少的操作次数,如果无解输出-1。
输入输出样例
5
13
-3
-4
-5
62
2
说明
【样例解释】
首先选择区间[2,4],之后数列变成1,9,-4,7,50,然后选择[3,3],数列变成1,5,4,3,50
Solution:
本题贼有意思。
用$s_i$表示$i$的前缀和,那么$s_y-s_{x-1}=T$表示的就是区间$[x,y]$的和,然后我们按照题目中的操作去搞,$a_{x-1}+T,a_{x}-T,a_{y}-T,a_{y+1}+T$,不难发现$s_x,s_y$实际上不变,然后因为$s_y=s_{x-1}+T$则操作等价于交换了$s_{x-1},s_{y}$两值。我们要使得$a_i$均为正数,就得让前缀和单调上升,那么很显然当$s_i\leq 0$或者$s_i=s_j,i\neq j$时无解,由于我们只关心前缀和的大小而非具体的值,所以直接对其离散化,然后就是建边统计一下各个环内的交换次数就好了。
代码:
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=2e5+;
int n,cnt,ans,to[N],net[N],h[N];
ll *q[N],s[N];
bool vis[N]; il int gi(){
int a=;char x=getchar();bool f=;
while((x<''||x>'')&&x!='-')x=getchar();
if(x=='-')x=getchar(),f=;
while(x>=''&&x<='')a=(a<<)+(a<<)+x-,x=getchar();
return f?-a:a;
} il bool cmp(const ll *a,const ll *b){return *a < *b;} il void add(int u,int v){to[++cnt]=v,net[cnt]=h[u],h[u]=cnt;} il void dfs(int u){
for(int i=h[u];i;i=net[i])
if(!vis[to[i]]) vis[to[i]]=,ans++,dfs(to[i]);
} int main(){
n=gi();
For(i,,n) {
s[i]=s[i-]+gi(),q[i]=&s[i];
if(s[i]<=)puts("-1"),exit();
}
sort(q+,q+n+,cmp);
ll lst=-;
For(i,,n)
if(*q[i]!=lst) lst=*q[i],*q[i]=++cnt;
else *q[i]=cnt,puts("-1"),exit();
For(i,,n) if(i!=s[i]) add(i,s[i]);
For(i,,n) if(!vis[i]) vis[i]=,dfs(i);
cout<<ans;
return ;
}
P1667 数列的更多相关文章
- 洛谷P1667/[10.22 模拟赛] 数列 (思维+模拟)
洛谷P1667 数列 题目描述 给定一个长度是n的数列A,我们称一个数列是完美的,当且仅当对于其任意连续子序列的和都是正的.现在你有一个操作可以改变数列,选择一个区间[X,Y]满足\(A_X +A_{ ...
- 【洛谷 P1667】 数列 (贪心)
题目链接 对于一个区间\([x,y]\),设这个区间的总和为\(S\) 那么我们在前缀和(设为\(sum[i]\))的意义上考虑到原操作其实就是\(sum[x−1]+=S\) , \(sum[x]+S ...
- C#求斐波那契数列第30项的值(递归和非递归)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- BZOJ1500[NOI2005]维修数列
Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一 ...
- PAT 1049. 数列的片段和(20)
给定一个正数数列,我们可以从中截取任意的连续的几个数,称为片段.例如,给定数列{0.1, 0.2, 0.3, 0.4},我们有(0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1 ...
- 斐波拉契数列加强版——时间复杂度O(1),空间复杂度O(1)
对于斐波拉契经典问题,我们都非常熟悉,通过递推公式F(n) = F(n - ) + F(n - ),我们可以在线性时间内求出第n项F(n),现在考虑斐波拉契的加强版,我们要求的项数n的范围为int范围 ...
- fibonacci数列(五种)
自己没动脑子,大部分内容转自:http://www.jb51.net/article/37286.htm 斐波拉契数列,看起来好像谁都会写,不过它写的方式却有好多种,不管用不用的上,先留下来再说. 1 ...
- js中的斐波那契数列法
//斐波那契数列:1,2,3,5,8,13…… //从第3个起的第n个等于前两个之和 //解法1: var n1 = 1,n2 = 2; for(var i=3;i<101;i++){ var ...
- 洛谷 P1182 数列分段Section II Label:贪心
题目描述 对于给定的一个长度为N的正整数数列A[i],现要将其分成M(M≤N)段,并要求每段连续,且每段和的最大值最小. 关于最大值最小: 例如一数列4 2 4 5 1要分成3段 将其如下分段: [4 ...
随机推荐
- Flume直接对接SaprkStreaming的两种方式
一.flume对接sparkStreaming的两种方式: Push推送的方式 Poll拉取的方式 第一种Push方式: 代码如下: package cn.itcast.spark.day5 impo ...
- Linux 下获取通讯IP
#!/bin/sh # filename: get_net.sh default_route=$(ip route show) default_interface=$() address=$(ip a ...
- 一个只有十行的精简MVVM框架(上篇)
本文来自网易云社区. 前言 MVVM模式相信做前端的人都不陌生,去网上搜MVVM,会出现一大堆关于MVVM模式的博文,但是这些博文大多都只是用图片和文字来进行抽象的概念讲解,对于刚接触MVVM模式的新 ...
- RSA加密通信小结(一)
一.背景描述 帮朋友完成相关方案的改进. 二.计划与方案 1.加密方式采用RSA 1024加密. 2.发送与接收都采用RSA加密,采用两套不同的密钥. 3.统一的加解码函数.(此处除了对于传输数据进行 ...
- eclipse注释快捷键
1.单行注释 注释: ctrl + / 取消注释: ctrl + / 多行注释 注释: ctrl shift + / 取消注释: ctrl shift + \
- python3-声音处理
先来说下二进制读写文件,这需要struct库 #二进制文件读写 import struct a= b=- # print(struct.pack("h",b)) # print(s ...
- docker 命令笔记
docker images 查看镜像 docker search 查找镜像 docker pull 拉取镜像 docker push 推送镜像 docker ps 查看正在运行的容器 docker p ...
- Activity生命周期 与 Activity 之间的通信
一. Activity生命周期 上图 1. Activity状态 激活状态 : Activity出于前台 , 栈顶位置; 暂停状态 : 失去了焦点 , 但是用户仍然可以看到 , 比如弹出一个对话框 , ...
- SDUST OJ 时间类的加、减法赋值运算
Problem F: 时间类的加.减法赋值运算 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 3801 Solved: 2210[Submit][St ...
- 软工实践Alpha冲刺(3/10)
队名:我头发呢队 组长博客 作业博客 杰(组长) 过去两天完成了哪些任务 继续翻阅Google Material Design 2的官方文档 接下来的计划 音源爬取 还剩下哪些任务 app开发 燃尽图 ...