子排列分析 解题报告

其中,$n \leq 1e5 $
看到题,没有头绪;用脑子思考后,没有头绪。因此抛弃脑子,直接打暴力。
通过暴力算法,我们可以发现,符合条件的排列数量一定是严格不上升的。
进一步研究发现:若 \([l,r]\) 不满足条件,则 \([l,r+1]\) 一定不满足条件。
下面是证明:已知 \([l,r]\) 不满足条件,那么一定存在二元组 \((i,j)\) 使得在 \(a_{i-l+1}<a_{j-l+1}\) 且 \(a_i>a_j\)。那么对于 \([l,r+1]\),因为 \(l\) 没有变化,所以这样的二元组 \((i,j)\) 一定仍然存在,所以 \([l,r+1]\) 一定不符合条件。
通过暴力几组数据可以发现,对于绝大部分的数据,符合条件的子串不会很多,所以考虑对利用结论对暴力算法进行优化。
具体地,我们记录每一次符合条件子串的左端点,并在下一次匹配中只匹配以这些左端点开头的字串。当符合条件的子串个数为0时,马上退出循环。
启示:暴力出奇迹
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
inline int max(int x,int y){return x>y?x:y;}
const int N=1e5+100;
typedef long long ll;
int n,a[N],b[N],rk[N],rk0[N],cnt,pre[N],tot;
ll ans;
int main()
{
freopen("sub.in","r",stdin);
freopen("sub.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",a+i),pre[i]=i+1;
tot=n-1;
for(int len=1,old;len<=n;len++){
if(tot==0) break;
cnt=1;
for(int k=1;k<=len;k++) b[k]=a[k];
sort(b+1,b+len+1,less<int>());
for(int k=1;k<=len;k++) rk0[b[k]]=k;
old=tot,tot=0;
for(int id=1;id<=old;id++){
int i=pre[id];
if(i+len-1>n) continue;
for(int k=1;k<=len;k++) b[k]=a[i+k-1];
sort(b+1,b+len+1,less<int>());
for(int k=1;k<=len;k++) rk[b[k]]=k;
bool flag=true;
for(int k=1;k<=len;k++)
if(rk[a[i+k-1]]!=rk0[a[k]]){
flag=false;
break;
}
if(flag){
cnt++;
pre[++tot]=i;
//printf("[ %d , %d ] ",i,j);
}
}
ans=max(ans,1ll*cnt*len);
//putchar('\n');
}
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号