[ABC354F] Useless for LIS

写在最前面的话:如果你懂这道题的线段树或者树状数组解法,那么本题解对你可能没有帮助。

题目传送门(Luogu)
题目传送门(AtCoder)

[ABC354F] Useless for LIS

题面翻译

  • 给定一个长度为 n 的序列 a。求出所有 i 使得存在任意一个 a 的最长上升子序列包含 i。多测。
  • 1T,n,n2×1051ai109

题目描述

長さ N の整数列 A が与えられます。

t = 1, 2,  ,N について、 AtA の最長増加部分列に含まれることがあるか判定してください。

AtA の最長増加部分列に含まれることがあるとは、以下のことをいいます。

  • 最長増加部分列の長さを L とする。各要素が 1 以上 N 以下の単調増加な整数列 i = (i1, i2,  ,iL) (i1 

    • Ai1
    • ある k (1  k  L) が存在して ik = t である

T 個のテストケースが与えられるので、それぞれについて答えを求めてください。

最長増加部分列とは?列 A の部分列とは A の要素をいくつか抜き出して元の順に並べてできる列を指します。

A の最長増加部分列とは、 A の狭義単調増加な部分列のうち列の長さが最大のものを指します。

输入格式

入力は以下の形式で標準入力から与えられる。

T case1 case2 caseT

ここで caseii 番目のケースの入力を意味する。各ケースは以下の形式で与えられる。

N A1 A2 AN

输出格式

以下の形式で出力せよ。

answer1 answer2 answerT

ここで answerii 番目のケースの出力を意味する。各ケースについては、次の通りである。

AtA の最長増加部分列に含まれることがある tm 個存在し、昇順に i1, i2,  ,im であったとする。このとき、以下の形式で出力せよ。

m i1 i2 im

样例 #1

样例输入 #1

1
5
2 1 4 5 3

样例输出 #1

4
1 2 3 4

样例 #2

样例输入 #2

2
6
2 5 3 4 3 4
5
10000 1000 100 1 10

样例输出 #2

5
1 3 4 5 6
2
4 5

提示

制約

  • 1  T  2 × 105
  • 1  N  2 × 105
  • 1  Ai  109
  • 全てのテストケースにおける N の総和は 2 × 105 以下

Sample Explanation 1

最長増加部分列の 1 つは (2, 4, 5) で、長さは 3 です。(1, 4, 5) も最長増加部分列の 1 つです。しかし、 A5 を含む最長増加部分列はありません。 よって、 1, 2, 3, 4 を出力します。

题目解析

给你一个长度为 N 的序列,问你那些元素有可能出现在最长上升子序列中。N2×105

首先,一个个枚举最长上生子序列然后记录肯定不行(可以用搜索做,但 N 很大,试问 22×105 会不会TLE),而且第一反应应该是动态规划,而且是二分优化的动态规划(NlogN 不会超)。可以枚举每个 ai,然后看看 ai 能不能和其他元素一起构成一个长度等于原序列最长上生子序列长度的子序列,这个包含 ai 的自序列就可以拆成两部分算:ai 和小于 ai的,ai 和大于 ai 的(ai 算了两次,算的时候要减一),也就是以 ai 结尾的和以 ai 开头的。把它们的长度加起来减去一,如果等于原序列最长上生子序列的长度,i 就是答案之一。

ai 结尾的最长上升自序列的长度好算,那么以 ai 开头的最长上生子序列怎么算呢?把 a 序列倒过来(相当于reverse),然后给每个元素取反(乘以负一),对新得到的序列(暂且称其为 b)求以 bi 结尾的最长上升自序列,那么 ai 开头的最长上升自序列的长度就等于以 bni+1 结尾的最长上升自序列。

AC code(请不要介意我奇怪的码风):

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int T,n,a[N],f[N],dp[N],cnt,b[N],f2[N],dp2[N],cnt2;
int main(){
	//freopen("xx.in","r",stdin);
	//freopen("xx.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>T;
	while(T--){
		cnt=0;
		cnt2=0;
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		for(int i=1;i<=n;i++){
			if(a[i]>f[cnt]){
				f[++cnt]=a[i];
				dp[i]=cnt;
			}else{
				int x=lower_bound(f+1,f+cnt+1,a[i])-f;
				x=min(x,cnt);
				dp[i]=x;
				f[x]=a[i];
			}
		}
		for(int i=1;i<=n;i++){
			b[i]=a[n-i+1];
			b[i]=-b[i];
		}
		f2[0]=INT_MIN;
		for(int i=1;i<=n;i++){
			if(b[i]>f2[cnt2]){
				f2[++cnt2]=b[i];
				dp2[i]=cnt2;
			}else{
				int x=lower_bound(f2+1,f2+cnt2+1,b[i])-f2;
				x=min(x,cnt);
				dp2[i]=x;
				f2[x]=b[i];
			}
		}
		int maxs=0;
		for(int i=1;i<=n;i++){
			maxs=max(maxs,dp[i]);
		}
		int cnt=0;
		for(int i=1;i<=n;i++){
			if(dp[i]+dp2[n-i+1]-1==maxs){
				cnt++;
			}
		}
		cout<<cnt<<"\n";
		for(int i=1;i<=n;i++){
			if(dp[i]+dp2[n-i+1]-1==maxs){
				cout<<i<<" ";
			}
		}
		cout<<"\n";
	}
	return 0;
}

附:人生第一次 Unknown Error,所以在AtCoder上交的

完结撒花!

posted @   吴一鸣  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示