【题解】CF1575L 题解

CF1575L 题解

思路分析

一道挺不错的思维题。

首先,我们定义 did_i 为要操作的次数,即 iaii-a_i(前提是 iaii \ge a_i,否则我们定义 did_i 不存在,即 did_i 必须大于等于零)。那么,当 aia_iaja_ji<ji < j)能通过操作多次使得 i=aii=a_ij=ajj=a_j 时,必然满足以下条件(充分必要条件):

{ai<ajdidj\begin{cases}a_i < a_j\\d_i \leq d_j\end{cases}

这里我来证明一下这个结论。

证明:设当 di>djd_i > d_j 时,亦能满足 aia_iaja_ji<ji < j)能通过操作多次使得 i=aii=a_ij=ajj=a_j

{i<jai<ajdi>dj\begin{cases}i<j\\a_i < a_j \\d_i > d_j \\\end{cases}

设有

{i+x=jai+y=aj\begin{cases}i+ x = j\\a_i + y = a_j \\\end{cases}

x,  y>0x,\;y > 0

did_i 定义,di+dj0d_i+d_j \geq 0di=iaid_i=i-a_idj=jajd_j=j-a_j

di+dj=iai+jaj=iai+i+x(ai+y)=2i2ai+xy\begin{aligned}d_i+d_j & = i-a_i+j-a_j \\ & = i-a_i + i+x-(a_i+y) \\ & = 2i - 2a_i+x-y\end{aligned}

由于 di=iai0d_i = i-a_i \geq 0,所以 xy0x - y \geq 0xyx \geq y

di>djd_i > d_jdidj>0d_i-d_j > 0

didj=iai(jaj)=iai[i+x(ai+y)]=yx\begin{aligned}d_i-d_j & = i-a_i-(j-a_j) \\ & = i-a_i -[i+x-(a_i+y)] \\ & = y - x \\\end{aligned}

yx>0y-x>0,有 y>xy>x,即 x<yx < y,矛盾。

所以,当且仅当 didjd_i \leq d_j 时,满足 aia_iaja_ji<ji < j)能通过操作多次使得 i=aii=a_ij=ajj=a_j

接着,我们要尽可能多地去满足这两个条件。我们可以先确保满足一条件,再尽可能多地去满足第二个条件。于是,我们可以以 did_i 为第一关键字排序,这样可以先确保满足一条件。接着再求排序后 aia_i 的最长上升子序列,这样就可以尽可能多地去满足第二个条件了。

注意到 di0d_i \geq 0,所以要排除 i<aii < a_i 的情况。另外,nn 的范围较大,所以要使用快速求最长上升子序列的方法,我这里选用了使用树状数组求最长上升子序列的方法,详细可参考这篇博文

关键代码

int c[N], n, cnt; //树状数组,n,排除 i < a_i 后数的个数
struct node //(i-a_i,i) 二元组
{
	int i_ai, ai;	
}; 
node a[N];

int query(int x) //树状数组查询前 x 项的最值
{
	int sum = 0;
	while(x > 0)
	{
		sum = max(sum, c[x]);
		x -= lowbit(x);
	}
	return sum;
}

void update(int x, int p) //树状数组更新
{
	while(x <= n)
	{
		c[x] = max(c[x], p);
		x += lowbit(x);
	}
}

bool cmp(node x, node y) //以 i-a_i 为第一关键字排序的比较函数
{
	if(x.i_ai != y.i_ai) return x.i_ai < y.i_ai;
	return x.ai < y.ai;
}

signed main()
{
	cin >> n;
	for(int i = 1;i <= n;i++)
	{
		int t;
		cin >> t;
		if(i >= t) //满足要求
		{
			a[++cnt] = (node){i - t, t}; //插入序列
		}
	}
	int maxv = 0; //最长上升子序列的最长比较变量
	sort(a + 1, a + cnt + 1, cmp); //以 i-a_i 为第一关键字排序
	for(int i = 1;i <= cnt;i++)
	{
        // 使用树状数组求出最长上升子序列
		int y = query(a[i].ai - 1); 
		update(a[i].ai, y + 1);
		maxv = max(maxv, y + 1); //进行比较
	}
	cout << maxv << endl;
	return 0;
}
posted @ 2023-03-23 22:48  邻补角-SSA  阅读(11)  评论(0)    收藏  举报  来源