【题解】CF1575L 题解
CF1575L 题解
思路分析
一道挺不错的思维题。
首先,我们定义 为要操作的次数,即 (前提是 ,否则我们定义 不存在,即 必须大于等于零)。那么,当 与 ()能通过操作多次使得 且 时,必然满足以下条件(充分必要条件):
这里我来证明一下这个结论。
证明:设当 时,亦能满足 与 ()能通过操作多次使得 且 。
即
设有
()
由 定义,,,。
由于 ,所以 ,。
又 ,。
即 ,有 ,即 ,矛盾。
所以,当且仅当 时,满足 与 ()能通过操作多次使得 且 。
接着,我们要尽可能多地去满足这两个条件。我们可以先确保满足一条件,再尽可能多地去满足第二个条件。于是,我们可以以 为第一关键字排序,这样可以先确保满足一条件。接着再求排序后 的最长上升子序列,这样就可以尽可能多地去满足第二个条件了。
注意到 ,所以要排除 的情况。另外, 的范围较大,所以要使用快速求最长上升子序列的方法,我这里选用了使用树状数组求最长上升子序列的方法,详细可参考这篇博文。
关键代码
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;
}

浙公网安备 33010602011771号