• 模拟测试49


    这次考试题还是蛮好的,只是人很水啊

    T1

    考场思路:

    1.每次询问离线出来,再对于每一个k进行操作,$O(klnk)$枚举区间,再利用主席树查前驱,期望时间复杂度$O(nlogn^2)$但可以被卡到$O(n^2logn)$(对于k极小的询问),如果优化就把k极小的询问预处理?不可实现弃辽

    2.分块,不会处理每一块的答案,死了

    所以正解还是分块,考虑预处理每一块答案。

    对于一个k来说,答案是$max_{i=0}^{n/k}max_{j=i*k}^{i*k+k-1} {a[j]-i*k}$,开一个桶维护每一块内的元素,扫一边搞出<=每个数的数直接处理即可。复杂度为$O(n^2lnn/S+m*S)$当S取$sqrt{nlogn}$的时候最小为$O(nsqrt{nlogn})$

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<iostream>
     4 #define N 100001
     5 #define sN 105
     6 using namespace std;
     7 inline int _max(int a,int b){return a>b?a:b;}
     8 int bl[N+5],ans[sN][N+5],t[N+5],tl[N+5],tot,L[sN],a[N+5];
     9 inline int read()
    10 {
    11     int x=0,f=1;char c=getchar();
    12     while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    13     while(c>='0'&&c<='9')x=x*10+c-48,c=getchar();
    14     return x*f;
    15 }
    16 inline void pre()
    17 {
    18     int now;
    19     for(int i=1;i<=tot;i++)
    20     {
    21         now=L[i];
    22         while(bl[now]==i)t[a[now]]++,tl[a[now]]=a[now],now++;
    23         for(int j=1;j<=N;j++)if(!t[j])tl[j]=tl[j-1];now=L[i];
    24         for(int j=2;j<=N;j++)
    25         {
    26             for(int k=j-1;k<=N;k+=j)
    27                 ans[i][j]=_max(ans[i][j],(tl[k]%j));
    28             ans[i][j]=_max(ans[i][j],(tl[N]%j));
    29         }
    30         while(bl[now]==i)t[a[now]]--,tl[a[now]]=0,now++;
    31     }
    32 }
    33 inline int query(int l,int r,int k)
    34 {
    35     int mx=0;
    36     if(bl[l]==bl[r])
    37     {
    38         for(int i=l;i<=r;i++)mx=_max(mx,a[i]%k);
    39         return mx;
    40     }
    41     for(int i=l;bl[i]==bl[l];i++)mx=_max(mx,a[i]%k);
    42     for(int i=bl[l]+1;i<bl[r];i++)mx=_max(mx,ans[i][k]);
    43     for(int i=r;bl[i]==bl[r];i--)mx=_max(mx,a[i]%k);
    44     return mx;
    45 }
    46 int main()
    47 {
    48     int n=read(),m=read();
    49     int t=sqrt(n*20)+1;
    50     for(int i=1;i<=n;i++)
    51     {
    52         bl[i]=(i-1)/t+1;//printf("%d
    ",bl[i]);
    53         if(bl[i]!=bl[i-1])L[bl[i]]=i;
    54         a[i]=read();
    55     }tot=bl[n];pre();
    56     while(m--)
    57     {
    58         int l=read(),r=read(),k=read();
    59         printf("%d
    ",query(l,r,k));
    60     }
    61     return 0;
    62 }
    View Code

    T2

    n^2思路很简单,但是会被卡空间。

    所以换个角度,按x排序。

    实际上就是找不断往中间收缩的方案数(感性理解)

    考虑处理出前i-1个如何弄第i个,设dp[i][0/1]表示以i为起点往左/右走的方案数

    如果i是起点,那么给i加上前面比它小的往右撇的方案即可

    如果不是,那么i一定是第二个点,枚举起点和第三个点,给起点加上第三个点的贡献。

    得出转移方程:

    dp[i][0]+=dp[j][1] (j<i&&y[j]<y[i])

    dp[j][1]+=dp[z][1] (j<i&&z>j&&z<i&&y[z]<y[j]&&y[j]<y[i])

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define FH_SB 6005
     4 using namespace std;
     5 const int mod=1e9+7;
     6 int dp[FH_SB][2],s[FH_SB];
     7 struct node{
     8     int fh,sb;
     9     inline void init(){scanf("%d%d",&fh,&sb);}
    10     friend bool operator <(const node a,const node b){ return a.fh<b.fh;}
    11 }a[FH_SB];
    12 int main()
    13 {
    14     int n,ans=0;scanf("%d",&n);
    15     for(int i=1;i<=n;i++)a[i].init();
    16     sort(a+1,a+n+1);
    17     for(int i=1;i<=n;i++)
    18     {
    19         s[i]=1;dp[i][0]++;dp[i][1]++;
    20         for(int j=i-1;j;j--) s[j]=(s[j+1]+dp[j][1]*(a[j].sb<a[i].sb))%mod;
    21         for(int j=1;j<i;j++)
    22         {
    23             if(a[j].sb<a[i].sb)(dp[i][0]+=dp[j][1])%=mod;
    24             else (dp[j][1]+=s[j+1])%=mod;
    25         }
    26     }
    27     for(int i=1;i<=n;i++)(ans+=(dp[i][0]+dp[i][1])%mod)%=mod;
    28     printf("%d
    ",ans-n);
    29 }
    View Code

    T3不会,咕了。

  • 相关阅读:
    sizeof
    {面试题10: 二进制中1的个数}
    {面试题9: 斐波那契数列}
    gcc常用选项
    mount.nfs: access denied by server while mounting localhost:/home/xuwq/minilinux/system
    ubuntu bash提示找不到文件或目录
    linux 编译内核[scripts/kconfig/dochecklxdialog] 错误
    最简单的抓包程序
    linux命令行解析函数介绍
    逻辑地址到线性地址的转换
  • 原文地址:https://www.cnblogs.com/hzoi-kx/p/11566792.html
Copyright © 2020-2023  润新知