https://www.luogu.com.cn/problem/AT_abc354_f
題意:給定一個序列a,求出所有的i使得任意一個a的最長子序列包含i。
解法:我們先求這個序列的LIS的長度maxx,然後再去正著求一遍最長上升子序列和反著求一遍最長下降子序列即可,如果拼起來等於maxx那麼說明i這個點是滿足要求的點。
注意細節的處理,反著求最長下降子序列相當於把原序列取反後reverse一下然後再求一遍LIS。
vector<int> get(const std::vector<int> &a) {
const int n = a.size();
std::vector<int> f(n);
std::vector<int> g;
for (int i = 0; i < n; i++) {
auto it = std::lower_bound(g.begin(), g.end(), a[i]);
f[i] = it - g.begin();
if (it == g.end()) {
g.push_back(a[i]);
} else {
*it = a[i];
}
}
return f;
}
void solve()
{
int n;
cin>>n;
vector<int> a(n);
for(int i=0;i<n;i++)
{
cin>>a[i];
}
auto f = get(a);
reverse(all(a));
for(auto &x:a)
{
x*=-1;
}
auto g = get(a);
reverse(all(g));
for(int i=0;i<n;i++)
{
f[i]+=g[i];
}
int maxx = *max_element(all(f));
vector<int> ans;
for(int i=0;i<n;i++)
{
if(f[i]==maxx)
{
ans.push_back(i+1);
}
}
cout<<(int)ans.size()<<"\n";
for(auto x:ans)
{
cout<<x<<" ";
}
cout<<'\n';
}
https://www.luogu.com.cn/problem/AT_arc149_b
題意:給定兩個序列a,b,選一個下標i,swap(a[i],a[i+1]) swap(b[i],b[i+1]),可以操作任意次,問LIS(a)+LIS(b)的值最大是多少。
解法:如果我們位於i,我們考慮三種情況:
1.換了之後LIS(a)+1,LIS(b)-1,那麼這種操作對答案的貢獻肯定沒有影響,可以換
2.換了之後LIS(a)+1,LIS(b)+1 貢獻為正,可以換
3.兩者都是-1 ,貢獻為負,不換。
考慮到交換操作是兩序列同步進行的,那麼若a序列以最好的可能交換,是不會減少兩序列總體對答案的貢獻的。因為兩個序列都是排列,將b對映到a上,再將a從小到大排序即可。
int get(auto a)
{
vector<int> f;
for(auto x:a)
{
auto it = lower_bound(all(f),x);
if(it==f.end())
{
f.push_back(x);
}
else
{
*it = x;
}
}
return f.size();
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
vector<int> a(n),b(n);
for(int i=0;i<n;i++)
{
cin>>a[i];
}
for(int i=0;i<n;i++)
{
cin>>b[a[i]-1];
}
int len = get(b);
cout<<len+n<<'\n';
}
注意從下標為0輸入,輸入b[a[i]-1].