test20181005 序列
题意


考场30分
维护差值,考虑每次移动的变更,当前2-n位置上的差加1,1位置上的差减n-1。
然后要求的是绝对值的和,用吉司机线段树维护最大最小值、次大次小值。
期望复杂度\(O(n \log n)\)
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
typedef long long ll;
const int INF=0x7fffffff;
const int MAXN=2e6+7;
int n;
int ql,qr,v;
struct SegTree
{
	ll sumv[MAXN<<2];
	int minv[MAXN<<2],semi[MAXN<<2],numi[MAXN<<2]; // edit 2:long long
	int maxv[MAXN<<2],semx[MAXN<<2],numx[MAXN<<2];
	int addv[MAXN<<2];
#define lson (now<<1)
#define rson (now<<1|1)
	inline void pushup(int now)
	{
		sumv[now]=sumv[lson]+sumv[rson];
		minv[now]=min(minv[lson],minv[rson]);
		if(minv[lson]==minv[rson])
		{
			numi[now]=numi[lson]+numi[rson];
		}
		else
		{
			numi[now]=minv[lson]<minv[rson]?numi[lson]:numi[rson];
		}
		semi[now]=min(semi[lson],semi[rson]);
		semi[now]=min(semi[now],max(minv[lson],minv[rson]));
		maxv[now]=max(maxv[lson],maxv[rson]);
		if(maxv[lson]==maxv[rson])
		{
			numx[now]=numx[lson]+numx[rson];
		}
		else
		{
			numx[now]=maxv[lson]>maxv[rson]?numx[lson]:numx[rson];
		}
		semx[now]=max(semx[lson],semx[rson]);
		semx[now]=max(semx[now],min(maxv[lson],maxv[rson]));
	}
	void build(int now,int l,int r)
	{
		addv[now]=0;
		if(l==r)
		{
			sumv[now]=read();
			sumv[now]-=l;
			minv[now]=maxv[now]=sumv[now];
			numx[now]=numi[now]=1;
			semx[now]=0,semi[now]=n+1; // edit 3
			return;
		}
		int mid=(l+r)>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		pushup(now);
//		cerr<<"semx "<<l<<" -> "<<r<<" ="<<semx[now]<<endl;
	}
	inline void pushdown(int now,int l,int r)
	{
		if(addv[now])
		{
			int mid=(l+r)>>1;
			sumv[lson]+=(ll)addv[now]*(mid-l+1);
			minv[lson]+=addv[now],semi[lson]+=addv[now];
			maxv[lson]+=addv[now],semx[lson]+=addv[now];
			addv[lson]+=addv[now];
			sumv[rson]+=(ll)addv[now]*(r-mid);
			minv[rson]+=addv[now],semi[rson]+=addv[now];
			maxv[rson]+=addv[now],semx[rson]+=addv[now]; // edit 1
			addv[rson]+=addv[now];
			addv[now]=0;
		}
	}
	void add(int now,int l,int r)
	{
		if(ql<=l&&r<=qr)
		{
			sumv[now]+=(ll)(r-l+1)*v;
			minv[now]+=v,semi[now]+=v;
			maxv[now]+=v,semx[now]+=v;
			addv[now]+=v;
			return;
		}
		pushdown(now,l,r);
		int mid=(l+r)>>1;
		if(ql<=mid)
			add(lson,l,mid);
		if(qr>=mid+1)
			add(rson,mid+1,r);
		pushup(now);
	}
	ll qsum(int now,int l,int r)
	{
		if(ql<=l&&r<=qr)
		{
//			cerr<<l<<" -> "<<r<<" min="<<minv[now]<<" max="<<maxv[now]<<" semx="<<semx[now]<<" numx="<<numx[now]<<" sum="<<sumv[now]<<endl;
			if(minv[now]>=0)
			{
				return sumv[now];
			}
			if(maxv[now]<=0)
			{
				return -sumv[now];
			}
			if(minv[now]<0&&semi[now]>=0)
			{
				return sumv[now]-2LL*minv[now]*numi[now];
			}
			if(maxv[now]>=0&&semx[now]<0)
			{
				return -sumv[now]+2LL*maxv[now]*numx[now];
			}
		}
		pushdown(now,l,r);
		int mid=(l+r)>>1;
		ll ans=0;
		if(ql<=mid)
		{
//			cerr<<l<<" -> "<<r<<" lsum="<<qsum(lson,l,mid)<<endl;
			ans+=qsum(lson,l,mid);
		}
		if(qr>=mid+1)
		{
//			cerr<<l<<" -> "<<r<<" rsum="<<qsum(rson,mid+1,r)<<endl;
			ans+=qsum(rson,mid+1,r);
		}
//		cerr<<l<<" -> "<<r<<" sum="<<ans<<endl;
		return ans;
	}
}T;
void debug(int n)
{
	for(int i=1;i<=n;++i)
	{
		ql=qr=i;
		printf("%lld ",T.qsum(1,1,n));
	}
	ql=1,qr=n;
	printf("\n%lld\n",T.qsum(1,1,n));
}
int main()
{
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
	n=read();
	T.build(1,1,n);
	ql=1,qr=n;
	ll ans=T.qsum(1,1,n);
//	cerr<<"ans="<<ans<<endl;
//	debug(n);
	int p=1;
	for(int i=1;i<n;++i)
	{
		ql=1,qr=n,v=1;
		T.add(1,1,n);
		ql=p,qr=p,v=-n;
		T.add(1,1,n);
		++p;
		ql=1,qr=n;
		ans=min(ans,T.qsum(1,1,n));
//		cerr<<"ans="<<T.qsum(1,1,n)<<endl;
//		debug(n);
	}
	printf("%lld\n",ans);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}
然而并没有我想要的60分,1e5的数据我的程序要跑30s。
算了一下程序应该是\(O(n^{1.7})\)的,网上的\(O(n \log^2 n)\)都是以讹传讹。
后来学长告诉我吉司机线段树的复杂度上界被证明是\(O(n \log^3 n)\)的,非常有道理。
标解

解释一下题解所说的。
ans前两段的分类依据是过了符号点和过了起点。
线段树的做法是在维护ans序列。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#define M 6333333
#define rg register
#define LL long long
#define _min(a,b) ((a)<(b)?(a):(b))
#define open(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
char temp[1<<26],*S=temp,*T=temp;
char get()
{
	if(S == T)T+=fread(temp,1,1<<26,stdin);
	return *S++;
}
void re(rg int& x)
{
    rg char ch=get();x=0;
    while(ch<48)ch=get();
    while(47<ch)x=(x<<3)+(x<<1)+ch-48,ch=get();
}
using namespace std;
int n,big,sma,a[M],b[M];
LL ans,now;
int main()
{
	open(a);
	re(n);
	for(int i=1;i<=n;++i)
	{
		re(a[i]);
		int x=a[i]-i;
		if(x >= 0)++big,now+=x;
		else ++sma,now+=-x,++b[-x]; // b=cnt
	}
	ans=now;
	for(int i=1;i<n;++i) // cal ansi
	{
		int x=a[i]-1,y=a[i]-n;
		--big,now-=x;
		++sma,now+=-y,++b[-y+i];
		now+=big-sma+1;
		if(b[i])big+=b[i],sma-=b[i];
		ans=_min(ans,now);
	}
	printf("%lld\n",ans);
	return 0;
}
然而我没看懂这std写的是什么。
学长高招
考虑维护差值的数轴,数轴上存个数。
每一次操作原点向左移1个单位,ans的变化与正半轴、原点和负半轴上的差值的个数有关。
对s1变到sn的情况特殊处理就行了。
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x)
{
    T data=0;
	int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
		if(ch=='-')
			w=-1;
		ch=getchar();
	}
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;
const int MAXN=2e6+7;
int n,org,L,R;
ll ans,sum;
int a[MAXN],cnt[MAXN<<2];
int main()
{
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
	read(n);
	org=n<<1;
	for(int i=1;i<=n;++i)
	{
		read(a[i]);
		cnt[org+a[i]-i]++;
		if(a[i]-i<0)
			L++;
		else if(a[i]-i>0)
			R++;
		sum+=abs(a[i]-i);
	}
	ans=sum;
	for(int i=1;i<n;++i)
	{
		cnt[org+a[i]-1]--;
		if(a[i]-1>0)
			R--;
		sum+=abs(a[i]-n)-abs(a[i]-1);
		sum+=R+cnt[org]-L;
		R+=cnt[org],L-=cnt[org-1];
		org--;
		cnt[org+a[i]-n]++;
		if(a[i]-n<0)
			L++;
		ans=min(ans,sum);
	}
	printf("%lld\n",ans);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}
												
											test20181005 序列的更多相关文章
- 【夯实PHP基础】UML序列图总结
		
原文地址 序列图主要用于展示对象之间交互的顺序. 序列图将交互关系表示为一个二维图.纵向是时间轴,时间沿竖线向下延伸.横向轴代表了在协作中各独立对象的类元角色.类元角色用生命线表示.当对象存在时,角色 ...
 - Windows10-UWP中设备序列显示不同XAML的三种方式[3]
		
阅读目录: 概述 DeviceFamily-Type文件夹 DeviceFamily-Type扩展 InitializeComponent重载 结论 概述 Windows10-UWP(Universa ...
 - 软件工程里的UML序列图的概念和总结
		
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习! 软件工程的一般开发过程:愿景分析.业务建模,需求分析,健壮性设计,关键设计,最终设计,实现…… 时序图也叫序列图(交互图),属于软件 ...
 - python序列,字典备忘
		
初识python备忘: 序列:列表,字符串,元组len(d),d[id],del d[id],data in d函数:cmp(x,y),len(seq),list(seq)根据字符串创建列表,max( ...
 - BZOJ 1251: 序列终结者 [splay]
		
1251: 序列终结者 Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 3778 Solved: 1583[Submit][Status][Discu ...
 - 最长不下降序列nlogn算法
		
显然n方算法在比赛中是没有什么用的(不会这么容易就过的),所以nlogn的算法尤为重要. 分析: 开2个数组,一个a记原数,f[k]表示长度为f的不下降子序列末尾元素的最小值,tot表示当前已知的最长 ...
 - [LeetCode] Sequence Reconstruction 序列重建
		
Check whether the original sequence org can be uniquely reconstructed from the sequences in seqs. Th ...
 - [LeetCode] Binary Tree Longest Consecutive Sequence 二叉树最长连续序列
		
Given a binary tree, find the length of the longest consecutive sequence path. The path refers to an ...
 - [LeetCode] Repeated DNA Sequences 求重复的DNA序列
		
All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACG ...
 
随机推荐
- 20170814xlVBA PowerPoint分类插图加说明
			
Public Sub AddPictures() Dim ppApp As PowerPoint.Application Set ppApp = New PowerPoint.Application ...
 - 1月4日编程基础hash
			
早上git加星了webapp的教程 > h = Hash.new('Go Fishing') => {} // 创建一个空hash,设定"Go Fishing&qu ...
 - python-day34--并发编程之多线程
			
理论部分 一.什么是线程: 1.线程:一条流水线的工作过程 2.一个进程里至少有一个线程,这个线程叫主线程 进程里真正干活的就是线程 3.进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资 ...
 - ora2pg安装及卸载
			
--ora2pg安装 tar xzf ora2pg-10.x.tar.gz or tar xjf ora2pg-10.x.tar.bz2 cd ora2pg-10.x/ perl Makefile. ...
 - 基于高通 qca4531 mp3 demo板 双系统引导设计
			
为了系统和稳定性,flash上有两套系统.在uboot引导阶段会根据当前的bootslot变量,决择运行哪套系统.进入系统之后,会自动挂载数据区,然后启动开关的应用程序. 如上图所示系统有两块存储芯片 ...
 - gitlba的搭建与使用
			
实验环境继续使用git的实验环境,详情请点击连接https://www.cnblogs.com/cash-su/p/10131632.html 首先给服务器做一个本机的映射 [root@git1 ~] ...
 - 51nod1079
			
模板题... 代码: #include <iostream> using namespace std; ],p[]; int main() { int n; while(cin>&g ...
 - EHlib在数据单元中显示字段值为图形。
			
-[定制网格数据单元] 在数据单元中显示字段值为图形. TDBGridEh allows to show bitmaps from TImageList component depending o ...
 - PHP生成GIF动态图片验证码
			
<?php /** * 调用示例 * */ session_start(); $randCode = ''; //验证码随机 $str="abcdefghjkmnpqrstuvwsyz ...
 - ipython与sublime调用其shell出现的问题
			
本机电脑 win10 已安装python3.5 1. 直接在命令行运行 pip install ipython[all] 安装 ipython 安装完成后 在命令行输入 jupyter note ...