bzoj 3043: IncDec Sequence 模拟

3043: IncDec Sequence

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 248  Solved: 139
[Submit][Status]

Description

给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一。
问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。

Input

第一行一个正整数n 
接下来n行,每行一个整数,第i+1行的整数表示ai。

Output

第一行输出最少操作次数
第二行输出最终能得到多少种结果

Sample Input

4
1
1
2
2

Sample Output

1
2

HINT

对于100%的数据,n=100000,0<=ai<2147483648

  正解传送门:http://blog.csdn.net/willinglive/article/details/38419573

  我看到这道题时并没有想到正解,但是很容易yy出来修改策略,每次填满最低的那一段区间,像涨水一样一直涨到顶端,离散处理将低于x的所有值提升到x的增加次数,然后倒着在做一遍,如果暴力做的话肯定会TLE,我们观察每次增加的区间数量即为低于x的区间联通块数量,这不是涨水求联通数的裸题?。。。。

  最后,因为我先离散化了所有点,所以如果我想回答询问2的话,需要回答离散之前的位置个数,这一点很容易wa。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 110000
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
typedef long long qword;
int a[MAXN];
pair<int,int> b[MAXN];
int c[MAXN];
int n,m;
qword v1[MAXN],v2[MAXN];
int uf[MAXN];
int get_fa(int now)
{
        return uf[now]==now ? now : uf[now]=get_fa(uf[now]);
}
int comb(int x,int y)
{
        x=get_fa(x);
        y=get_fa(y);
        if (x==y)return false;
        uf[x]=y;
        return true;
}
int main()
{
        freopen("input.txt","r",stdin);
        scanf("%d",&n);
        int i,j,k;
        for (i=0;i<n;i++)
        {
                scanf("%d",a+i);
                b[i].first=a[i];
                b[i].second=i;
                c[i]=a[i];
        }
        sort(c,c+n);
        m=unique(c,c+n)-c;
        sort(b,&b[n]);
        int nowc=0;
        qword tot=0;
        int x,y;
        for (i=0;i<n;i++)uf[i]=i;
        for (i=0;i<n;i++)
        {
                x=b[i].second;
                tot++;
                if (x && a[x-1]<=a[x])
                        tot-=comb(x-1,x);
                if (x<n-1 && a[x+1]<a[x])
                        tot-=comb(x+1,x);
                if (i!=n-1 && b[i+1].first!=b[i].first)
                {
                        v1[nowc+1]=v1[nowc]+tot*(c[nowc+1]-c[nowc]);
                        nowc++;
                }
        }
        nowc=m-1;
        tot=0;
        for (i=0;i<n;i++)uf[i]=i;
        for (i=n-1;i>=0;i--)
        {
                x=b[i].second;
                tot++;
                if (x<n-1 && a[x+1]>=a[x])
                        tot-=comb(x+1,x);
                if (x && a[x-1]>a[x])
                        tot-=comb(x-1,x);
                if (i && b[i-1].first!=b[i].first)
                {
                        v2[nowc-1]=v2[nowc]+tot*(c[nowc]-c[nowc-1]);
                        nowc--;
                }
        }
        qword ans=INFL;
        int mina=INF,maxa=-INF;
        for (i=0;i<m;i++)
        {
                if (v1[i]+v2[i]<ans)
                {
                        ans=v1[i]+v2[i];
                        mina=INF,maxa=-INF;
                }
                if (v1[i]+v2[i]==ans)
                        mina=min(mina,c[i]),maxa=c[i];
        }
        printf("%lld\n%d\n",ans,maxa-mina+1);
}
时间: 2024-10-24 08:52:45

bzoj 3043: IncDec Sequence 模拟的相关文章

BZOJ 3043: IncDec Sequence

3043: IncDec Sequence Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 578  Solved: 325[Submit][Status][Discuss] Description 给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一.问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种. Input 第一行一个正整数n 接

BZOJ 3043 IncDec Sequence 差分

题目大意:给定一个序列,提供一个操作:将某个区间内所有数+1或-1 求将所有数变成一样最少多少次操作,以及最终可以有多少种数 考虑差分后的序列 每次对[l,r]进行+1/-1,相当于在差分后的数组上对l进行+1/-1,然后对r+1进行-1/+1 特殊的,如果r=n,那么就相当于对l进行了+1/-1 我们最终的目标是将差分数组变成第一个位置是最终的数字,2~n都是0 那么我们统计差分后的数组的2~n号位置上每个位置上的数 令pos为所有正数的和,neg为所有负数的和的绝对值 那么首先是pos和ne

【BZOJ 3043】 3043: IncDec Sequence (差分)

3043: IncDec Sequence Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 589  Solved: 332 Description 给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一.问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种. Input 第一行一个正整数n 接下来n行,每行一个整数,第i+1行的整数表示ai.

BZOJ3043: IncDec Sequence

3043: IncDec Sequence Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 233  Solved: 132[Submit][Status] Description 给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一.问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种. Input 第一行一个正整数n 接下来n行,每行一个

2498 IncDec Sequence

2498 IncDec Sequence 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description 给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一. 问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种. 输入描述 Input Description 第一行一个正整数n  接下来n行,每行一个整数,第i

bzoj 1367: [Baltic2004]sequence

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MB Description Input Output 一个整数R Sample Input 7 9 4 8 20 14 15 18 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15,18.R=13 详细证明请看IOI2005国家集训队论文  黄源河 https://wenku.baidu.com/view/20e9ff18964b

UVA 1594:Ducci Sequence (模拟 Grade E)

题意: 对于一个n元组(a0,a1,...),一次变换后变成(|a0-a1|,|a1-a2|,...) 问1000次变换以内是否存在循环. 思路: 模拟,map判重 代码: #include <cstdio> #include <cstring> #include <map> #include <cmath> #include <algorithm> using namespace std; struct Node{ int a[16]; int

bzoj 2741: 【FOTILE模拟赛】L 分塊+可持久化trie

2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1116  Solved: 292[Submit][Status] Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y):

[BZOJ入门OJ2092][Noip模拟题]舞会

2092: [Noip模拟题]舞会 Time Limit: 20 Sec  Memory Limit: 256 MB Submit: 9  Solved: 5 [Submit][Status][Web Board] Description 学校举行舞会啦,一共有N个人参加,所有人站成一排,从左开始编号,最左边的人编号为1 ,最右边的为N.每个人跳舞的熟练度我们用一个整数表示,第i个人的熟练度为Ai,每次熟 练度最接近的一对相邻男女会出列跳舞,如果有多对那么最左边的那一对会先出列,请你给 出出列跳