zoukankan      html  css  js  c++  java
  • [雅礼NOIP2018集训 day1]

    现在才来填坑,之后还要陆续补其他几天的,可能前几天真的太颓了


    T1:

    题目大意:给定一个长度为n的序列,m次询问每次询问给出l,r,询问区间l到r的元素在模k意义下的最大值

    数据范围当然是你暴力写不过的...

    老实说我考场敲了主席树,不幸的是只拿到了暴力的分

    考虑正解?我们分块。预处理出每一块在模k意义下的最大值,多余部分暴力计算就好

    上面一句话显然是废话,我么怎么预处理出每一块在模任意k意义下的最大值呢?

    显然在$[ak,(a+1)k)$这一段值域中,数值最大值一定是最优的,我们可以开个表记录当前块中小于等于当前数字的最大的元素的大小,预处理统计一段的答案时就是取小于等于$(a+1)k-1$的最大值就好了

    发现$[ak,(a+1)k)$的区间一共有$klnk$个,其实我也不知道怎么得到的,这样时间复杂度好像就对了,实测卡过去是比较轻松的

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    
    const int N=1e5;
    const int M=1e2;
    int n,m;
    int a[N+5],lst[N+5],ans[M][N+5];
    inline int read()
    {
        char ch=getchar();
        int s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    int main()
    {
    //    freopen("flower.in","r",stdin);
    //    freopen("flower.out","w",stdout);
        int B=1000;
        n=read();m=read();
        for (int i=1;i<=n;i++) a[i]=read();
        int siz=(n-1)/B;
        for (int i=0;i<=siz;i++)
        {
            memset(lst,0,sizeof(lst));
            int l=i*B+1,r=min(n,(i+1)*B);
            for (int j=l;j<=r;j++) lst[a[j]]=a[j];
            for (int j=1;j<=N;j++) lst[j]=max(lst[j],lst[j-1]);
            for (int j=1;j<=N;j++) for (int k=0;k<=N;k+=j) ans[i][j]=max(ans[i][j],lst[min(N,k+j-1)]-k);
        }
        while (m--)
        {
            int l=read(),r=read(),k=read();
            int L=(l-1)/B,R=(r-1)/B,re=0;
            for (int i=L+1;i<R;i++) re=max(re,ans[i][k]);
            for (int i=l;i<=min((L+1)*B,r);i++) re=max(re,a[i]%k);
            for (int i=max(l,R*B+1);i<=r;i++) re=max(re,a[i]%k);
            printf("%d
    ",re);
        }
        return 0;
    }
    View Code

    T2:

    emm这题出题人很坑啊,像笔者这样的蒟蒻在看到条件1的时候就直接按y排序了,出题人的意思是这样不好优化,笔者在考场上好像也许可能大概刚出了时间复杂度正确的前缀和优化,无奈死在了128MB的空间上

    正解是按x排序,$dp_{i,0/1}$表示以第i个点为顶端的向左和向右的方案数。注意到当前点的x值是最大的,那么显然只能在前i个点中只能作为折线的第一个点或第二个点

    那么有两种转移方法

    $dp_{j,1}->dp_{i,0}$  $y_j<y_i$

    $dp_{k,1}->dp_{j,1}$ $y_j>y_i,y_k<y_i,x_k>x_j$

    以上显然都有$x_i>x_j,x_i>x_k$

    发现第二种转移可以前缀和优化一下

    #include<algorithm>
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    
    const int N=6e3+15;
    const int mod=1e9+7;
    int n;
    ll dp[N][2];
    struct node
    {
        ll x,y;
    }e[N];
    inline ll read()
    {
        char ch=getchar();
        ll s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    bool cmp(node a,node b) {return a.x<b.x;}
    int main()
    {
        //freopen("refract.in", "r", stdin);
        //freopen("refract.out", "w", stdout);
        n=read();
        for (int i=1;i<=n;i++) {e[i].x=read();e[i].y=read();}
        sort(e+1,e+1+n,cmp);
        for (int i=1;i<=n;i++)
        {    
            dp[i][0]=dp[i][1]=1;
            for (int j=i-1;j>=1;j--) 
                if (e[j].y<e[i].y) (dp[i][0]+=dp[j][1])%=mod;
                else (dp[j][1]+=dp[i][0])%=mod;
        }
        ll ans=mod-n;//dp[i][0]和dp[i][1]算重了 
        for (int i=1;i<=n;i++) (ans+=dp[i][0]+dp[i][1])%=mod;
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    T3:

    待填

  • 相关阅读:
    poj2778 DNA Sequence(AC自动机+矩阵快速幂)
    poj2001 Shortest Prefixes (trie树)
    hdu5536 Chip Factory
    解决 苹果手机点击输入框页面自动放大111
    css 记录
    对复选框自定义样式 优化方法
    css引入外部字体
    jquery获取当前页面的URL信息
    左侧导行伸缩控制
    表单提交同类数据的做成数组
  • 原文地址:https://www.cnblogs.com/xxzh/p/9743189.html
Copyright © 2011-2022 走看看