2017-11-3 题解
T1
Description
求由 1 到 n 一共 n 个数字组成的所有排列中,逆序对个数为 k 的有多少个
Hint
乍一看是数学题
我们考虑递推 用f[i][j]表示1~i的所有排列中逆序对为k的有多少个
我们注意到把i加进去由于1~i-1都比i小,所以i可以产生0~i个逆序对
得到公式:$$f[i][j]=\sum_{k=0}^{i} {f[i-1][j-k]}$$
即$f[i][j]=f[i-1][j]+f[i-1][j-1]+…..+f[i-1][j-i]$
而我们注意到:$$f[i][j-1]=\sum_{k=0}^{i} {f[i-1][j-1-k]}$$
即$f[i][j-1]=f[i-1][j-1]+…..+f[i-1][j-1-k]+f[i-1][j-i]$
所以:$$f[i][j]=f[i][j-1]+f[i-1][j]-f[i-1][j-i]$$
这就是一个很简单很普遍的递推(动归)优化
而上式条件:$j<i$,同样的当$j≥i$时$$f[i][j]=\sum_{k=0}^{j} {f[i-1][j-k]}$$
通过一样的推导我们能得到:$$f[i][j]=f[i][j-1]+f[i-1][j]$$
最后我们输出f[n][k]-f[n][k-1]
Code
T2
Description
一个长度为$n(n\leq2000)$的序列,对于每个位置$i$的数$a_i$都有一个优美值,其定义是:找到序列中最长的一段$[l,r]$,满足$l≤i≤r$,且$[l,r]$中位数为$a_i$(我们比较序列中两个位置的数的大小时,以数值为第一关键字,下标为第二关键字比较.这样的话$[l,r]$的长度只有可能是奇数)$r-l+1$就是$i$的优美值.有Q个询问,每个询问$[l,r]$表示查询区间$[l,r]$内优美值的最大值
精简题意:对于任何一个$a_i$,它的优美值就是最大的包含它且以它的为中位数的区间的长度(这里要注意题意要求以双关键字排序),给定Q个询问求$[l,r]$中优美值的最大值
Hint
我们注意到对于一个特定的序列每个元素的优美值一定,所以我们只要求出每个优美值,问题就变成了求特定区间的最大值,就可以用RMQ解决
所以我们关键是求出每个元素的优美值,注意到数据范围我们只能$O(n^2)$做然后我就打炸了
然后就很简单了,向左把大于$a_i$的视为1,小于$a_i$的视为-1,向右把大于的视为-1小于的视为1
(如果不懂为什么要这么做可以去做一下“非常男女”计划)
Code
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#define siz 2100
using namespace std;
int n,m,s,t,cnt;
int a[siz],fir[siz*2],beauty_[siz],T[siz][20];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]),beauty_[i]=1;
for(int i=1;i<=n;++i) {
memset(fir,0,sizeof(fir));
fir[n]=i; //i=1时第一个循环不会进行要先赋值
cnt=0;
for(int j=i-1;j;--j) {
if(a[j]<=a[i]) cnt--; //注意这道题的"大于"和"小于"被重定义了
else cnt++;
fir[cnt+n]=j;
}
beauty_[i]=i-fir[n]+1; //i=n第二个循环不会进行要先赋值
cnt=0;
for(int j=i+1;j<=n;++j) {
if(a[j]>=a[i]) cnt--;
else cnt++;
if(fir[cnt+n]) beauty_[i]=max(beauty_[i],j-fir[cnt+n]+1);
}
T[i][0]=beauty_[i];
}
for(int j=1;(1<<j)<=n;++j)
for(int i=1;(i+(1<<j)-1)<=n;++i)
T[i][j]=T[i][j-1]>T[i+(1<<(j-1))][j-1]?T[i][j-1]:T[i+(1<<(j-1))][j-1];
scanf("%d",&m);
while(m--) {
scanf("%d%d",&s,&t);
int j=log2(t-s+1);
printf("%d\n",T[s][j]>T[t-(1<<j)+1][j]?T[s][j]:T[t-(1<<j)+1][j]);
}
return 0;
}
T3
Description
一开始你有一个空集,集合可以出现重复元素,然后有 Q 个操作
- add s
在集合中加入数字 s。 - del s
在集合中删除数字 s。保证 s 存在 - cnt s
查询满足a&s=a条件的 a 的个数
Hint
这看上去是一道数据结构题
我考场上分析:
要使a&s=a,则s一定要大于等于a(根据&定义很好分析),所以我们每次只要找比s小的a就好了
于是我打了一个二叉排序树希望多水一些分……
然后和暴力一样的分…..
正解:分块
//表示作为没打过分块的蒟蒻,先自学完再来打题解
Code
//待补充