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]=k=0if[i1][jk]

f[i][j]=f[i1][j]+f[i1][j1]+.....+f[i1][ji]
而我们注意到:
f[i][j1]=k=0if[i1][j1k]

f[i][j1]=f[i1][j1]+.....+f[i1][j1k]+f[i1][ji]
所以:
f[i][j]=f[i][j1]+f[i1][j]f[i1][ji]

这就是一个很简单很普遍的递推(动归)优化
而上式条件: j<i ,同样的当 ji
f[i][j]=k=0jf[i1][jk]

通过一样的推导我们能得到:
f[i][j]=f[i][j1]+f[i1][j]

最后我们输出f[n][k]-f[n][k-1]

Code

T2

Description

一个长度为 n(n2000) 的序列,对于每个位置 i 的数ai都有一个优美值,其定义是:找到序列中最长的一段 [l,r] ,满足 lir ,且 [l,r] 中位数为 ai (我们比较序列中两个位置的数的大小时,以数值为第一关键字,下标为第二关键字比较.这样的话 [l,r] 的长度只有可能是奇数) rl+1 就是 i 的优美值.有Q个询问,每个询问[l,r]表示查询区间 [l,r] 内优美值的最大值

精简题意:对于任何一个 ai ,它的优美值就是最大的包含它且以它的为中位数的区间的长度(这里要注意题意要求以双关键字排序),给定Q个询问求 [l,r] 中优美值的最大值

Hint

我们注意到对于一个特定的序列每个元素的优美值一定,所以我们只要求出每个优美值,问题就变成了求特定区间的最大值,就可以用RMQ解决
所以我们关键是求出每个元素的优美值,注意到数据范围我们只能 O(n2)
然后我就打炸了
然后就很简单了,向左把大于 ai 的视为1,小于 ai 的视为-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 个操作
1. add s
在集合中加入数字 s。
2. del s
在集合中删除数字 s。保证 s 存在
3. cnt s
查询满足a&s=a条件的 a 的个数

Hint

这看上去是一道数据结构题
我考场上分析:
要使a&s=a,则s一定要大于等于a(根据&定义很好分析),所以我们每次只要找比s小的a就好了
于是我打了一个二叉排序树希望多水一些分……
然后和暴力一样的分…..

正解:分块
//表示作为没打过分块的蒟蒻,先自学完再来打题解

Code

//待补充


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值