• [4.30四校联考]


    来自FallDream的博客,未经允许,请勿转载,谢谢。


    不得不说厦一的机子还是快 (其实数据也蛮水的) 交了两个暴力 一个骗分(我不会告诉你特判都写挂了的) 居然拿到了95+100+10

    A.T组数据,每次给你n个数ai(T<=15,n<=40,ai<=5e7) 你要选出一些数使得总和大等于m且总和最小。

    很容易想到双向宽搜 但是对接的时候要把两个2^20大小的数组排序,所以写一个归并/基数排序就行啦。

    反正我是没想到  写了一个挺玄学的 把权值分段存到vector里面 然后暴力查...本机根本跑不过,随机数据大概1.3s,评测的时候只RE了一个点,好几个点1.000s卡过(稳健)

    我的sb做法

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #define MN 500001
    #define INF 2100000000
    #define MX 1000000000
    #define getchar() (*S++) 
    char B[1<<15],*S=B;
    using namespace std;
    inline int read()
    {
        int x = 0; char ch = getchar();
        while(ch < '0' || ch > '9')  ch = getchar();
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x;
    }
    
    vector<int> V[MN+5];
    int ans,ne[MN+5],T,n,m,tot,lim,a[45],mn[MN+5];
    inline void R(int&x,int y){y<x?x=y:0;}
    inline void Solve(int x)
    {
        if(x>=m){ans=min(ans,x);return;}
        if(x>m+MX) return;
        int num=ne[(m-x)/2000];
        if(num!=-1)
        {
            if(mn[num]>=m-x) ans=min(ans,mn[num]+x);
            else if(mn[num]+x<ans)
            {
                for(int i=0;i<V[num].size();++i)
                    V[num][i]+x>=m?(R(ans,V[num][i]+x),0):0;
            }
        }
    }
    void Dfs1(int x,int v)
    {
        if(x>lim) {int vv=v/2000;V[vv].push_back(v);R(mn[vv],v);return;}    
        Dfs1(x+1,v);if(v<m)Dfs1(x+1,v+a[x]);
    }
    
    void Dfs2(int x,int v)
    {
        if(x==lim){Solve(v);return;}
        Dfs2(x-1,v);if(v<m)Dfs2(x-1,v+a[x]); 
    }
    
    void Dfs3(int x,int v)
    {
        if(x>lim) {ne[v]=v;return;}    
        Dfs3(x+1,v);if(v<m)Dfs3(x+1,v+a[x]);
    }
    
    void Dfs4(int x,int v)
    {
        if(x==lim){ans=min(ans,v>=m?v:(v+ne[m-v]));return;}
        Dfs4(x-1,v);if(v<m)Dfs4(x-1,v+a[x]); 
    }
    
    void Solve1()
    {
        for(int i=0;i<=MN;++i) ne[i]=0;
        lim=n/2;
        Dfs3(1,0);
        for(int i=MN,last=INF;~i;--i) 
        {
            if(ne[i]) last=i;
            ne[i]=last;    
        }
        Dfs4(n,0);
    }
    
    void Solve2()
    {
        for(register int i=0;i<=MN;i+=2) V[i].clear(),mn[i]=INF,V[i+1].clear(),mn[i+1]=INF;
        lim=n/2;Dfs1(1,0);
          for(register int i=MN,last=-1;~i;--i) 
            V[i].size()?last=i:0,ne[i]=last;
        Dfs2(n,0);    
    }
    
    int main()
    {
        freopen("challenge.in","r",stdin);
        freopen("challenge.out","w",stdout);
        fread(B,1,1<<15,stdin);
        for(T=read();T;--T)
        {
            n=read();m=read();ans=INF;tot=0;
            for(register int i=1;i<=n;++i)
                tot+=(a[i]=read());
            sort(a+1,a+n+1);
            if(tot<m) {puts("-1");continue;}
            if(tot<=MN) Solve1();
            else Solve2();
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    正解的靠谱做法

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define rint register int
    #define INF 2000000000
    #define MN 1048600
    #define N 32768
    using namespace std;
    inline int read()
    {
        int x = 0; char ch = getchar();
        while(ch < '0' || ch > '9')  ch = getchar();
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x;
    }
    
    int a[MN+5],b[MN+5],s[45],top1,top2,T,m,n,ans,lim,tot=0,v[N+5],v2[N+5],sa[MN+5];
    
    void Dfs2(int x,int v)
    {
        if(x==lim){b[++top2]=v;return;}
        Dfs2(x-1,v);if(v<m) Dfs2(x-1,v+s[x]);
    }
    
    void Dfs1(int x,int v)
    {
        if(x>lim) {a[++top1]=v;return;}
        Dfs1(x+1,v);if(v<m) Dfs1(x+1,v+s[x]);
    }
    
    void Sort(int*s,int n)
    {
        for(rint i=0;i<N;++i) v[i]=v2[i]=0;
        for(rint i=1;i<=n;++i) ++v2[s[i]&(N-1)],++v[s[i]>>15];
        for(rint i=1;i<N;++i) v[i]+=v[i-1],v2[i]+=v2[i-1];
        for(rint i=1;i<=n;++i) sa[v2[s[i]&(N-1)]--]=s[i];
        for(rint i=n;i;--i) s[v[sa[i]>>15]--]=sa[i];
    }
    
    int main()
    {
        freopen("challenge.in","r",stdin);
        freopen("challenge.out","w",stdout);
        for(T=read();T;--T)
        {
            n=read();m=read();ans=INF;tot=0; 
            for(int i=1;i<=n;++i)
                tot+=(s[i]=read());
            if(tot<m) {puts("-1");continue;}
            top1=top2=0;lim=n>>1;
            Dfs1(1,0);Dfs2(n,0);
            Sort(a,top1);Sort(b,top2);
            for(rint i=1,j=top2;i<=top1;++i)
            {
                while(j>1&&b[j-1]+a[i]>=m) --j;
                if(b[j]+a[i]>=m) ans=min(ans,b[j]+a[i]);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }

    B.什么三角函数乱求导之类的 不会

    C.给一个由左右括号组成的序列,每次求一段区间的最长的合法括号序列的长度。  n,m<=30000

    我写了一个n^2的做法 还会爆内存 居然水过了 而且跑的飞快(数据不会都是随机的吧= =)

    std写了一个n根号log的做法 但是有个只有根号的做法..

    就是先预处理每个括号最近的可以匹配的括号,然后显然答案就是由一些这样的序列接起来的。

    考虑莫队,为了避免删除操作,考虑块内暴力,块外的话,每次计算左节点所在的块到右节点的答案,然后暴力移动到左节点计算答案

    在右指针右移的时候,维护每个点能匹配的最左边的且在左节点所在的块的右边的节点;每找到一个右括号,假设它能匹配的最近做括号的位置是pos,就看看pos-1是否是右括号且已经被匹配了,是的话就把两段接起来,这样移动的复杂度显然是O(1)的  然后移动左节点的时候把它和右边接起来就行了。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #define MN 30000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int n,m,size,block[MN+5],L[MN+5],Q[MN+5],top=0,Ans,R[MN+5],Res[MN+5],l,r,lt[MN+5],rt[MN+5];
    struct ques{int l,r,id;}q[MN+5];
    char st[MN+5];
    
    bool cmp(ques x,ques y){return block[x.l]==block[y.l]?x.r<y.r:x.l<y.l;}
    
    int main()
    {
        freopen("spell.in","r",stdin);
        freopen("spell.out","w",stdout);
        n=read();m=read();size=sqrt(n);
        scanf("%s",st+1);
        for(int i=1;i<=n;++i) block[i]=(i-1)/size+1;
        for(int i=1;i<=n;++i)
            if(st[i]=='(') Q[++top]=i;
            else if(top) L[i]=Q[top--];
        top=0;
        for(int i=n;i;--i)
            if(st[i]==')') Q[++top]=i;
            else if(top) R[i]=Q[top--];
        for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
        sort(q+1,q+m+1,cmp);
        for(int i=1,last=0;i<=m;++i)
        {
            if(last!=block[q[i].l])
            {
                memset(lt,0,sizeof(lt));
                memset(rt,0,sizeof(rt));
                l=r=block[q[i].l]*size+1;
                last=block[q[i].l];Ans=0;
            }
            if(block[q[i].r]==block[q[i].l])
            {
                int ans=0;top=0;
                for(int j=q[i].l;j<=q[i].r;++j)
                    if(st[j]=='(') Q[++top]=j,lt[j]=0;
                    else if(top)
                    {
                        lt[j]=(Q[top]>q[i].l&&lt[Q[top]-1])?lt[Q[top]-1]:Q[top];
                        --top,ans=max(ans,j-lt[j]+1);
                    }
                    else lt[j]=0;
                Res[q[i].id]=ans;
            }
            else
            {
                while(r<q[i].r)
                {
                    ++r;
                    if(L[r]>=l)
                    {
                        if(L[r]>l&&lt[L[r]-1]) lt[r]=lt[L[r]-1];
                        else lt[r]=L[r];
                        Ans=max(Ans,r-lt[r]+1);rt[lt[r]]=r;
                    }
                }    
                int ans=0;
                for(int j=l-1;j>=q[i].l;--j) if(R[j]&&R[j]<=r) 
                {
                    if(R[j]<l) rt[j]=rt[R[j]+1]?rt[R[j]+1]:R[j];
                    else rt[j]=R[j];
                    ans=max(ans,rt[j]-j+1);
                    if(rt[j]>=l-1) ans=max(ans,rt[rt[j]+1]-j+1);
                } 
                Res[q[i].id]=max(ans,Ans);
            }
        }
        for(int i=1;i<=m;i++) printf("%d
    ",Res[i]);
        return 0;
    }
  • 相关阅读:
    coding
    我的大学
    《活出生命的意义》读后感
    《世界是数字的》读后感
    学习进度表
    阅读《我是一只IT小小鸟有感》
    《软件工程师职业规范》心得
    软件工程第二次结对作业
    软件工程第三次作业
    软件工程第二次作业
  • 原文地址:https://www.cnblogs.com/FallDream/p/liankao430.html
Copyright © 2020-2023  润新知