zoukankan      html  css  js  c++  java
  • Codeforces940(A-F)

    A:给数组a,sort后求最长区间[l,r]使区间内max-min<=d,输出n-最长区间长度。

    题解:暴力。。。

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<queue>
    #include<vector>
    #define mp make_pair
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pa;
    const int N=1001;
    //struct E{int to,nxt;}e[N<<1];
    int n,a[N];
    int Write[20],WRI;
    void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
    void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));}
    //void add(LL x,LL y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;}
    //void Add(LL x,LL y){add(x,y); add(y,x);}
    int main()
    {
        //judge();
        n=read(); int d=read();
        for (int i=1;i<=n;i++) a[i]=read();
        int ans=1000000;
        sort(a+1,a+1+n);
        for (int i=1,j=1;i<=n;i++)
        {
            while (j<n&&a[j+1]-a[i]<=d) j++;
            ans=min(ans,n-(j-i+1));
        }
        printf("%d",ans);
        return 0;
    }
    View Code

    B:有一个数x=n,可以用A的金币使x--,或在x%k==0时用B的金币使x/=k,求将它变为1的最小代价。

    题解:贪心,先使x%=k,然后比较用A和B那个优,注意一些细节,没开long long爆了4发,┭┮﹏┭┮

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<queue>
    #include<vector>
    #define mp make_pair
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pa;
    //struct E{int to,nxt;}e[N<<1];
    LL n,A,B,k,x;
    int Write[20],WRI;
    void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    LL read(){LL d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
    void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));}
    //void add(LL x,LL y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;}
    //void Add(LL x,LL y){add(x,y); add(y,x);}
    int main()
    {
        //judge();
        n=read(); k=read(); A=read(); B=read();
        if (k==1)
        {
            printf("%lld",(n-1)*A);
            return 0;
        }
        x=n;
        LL ans=0;
        while (x!=1)
        {
            if (x<k) {ans+=(x-1)*A; break;}
            ans+=x%k*A;
            x-=x%k;
            if ((x-x/k)*A>B) ans+=B; else ans+=(x-x/k)*A;
            x/=k;
        }
        printf("%lld",ans);
        return 0;
    }
    View Code

    C:给一个字符串s,求字典序最小的字符串a,使a的长度为k,且a的字典序大于s,且a的字符集是s的子集

    题解:k>n时,在原串后加上k-n个s中最小字母即可,k<=n时,用类似进制加1的方法,使最后一位变为比它大的最小字符,如果它已经是最大的,就“进位”上去。

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<queue>
    #include<vector>
    #define mp make_pair
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pa;
    const int N=100010;
    //struct E{int to,nxt;}e[N<<1];
    int n,k,t,b[26];
    char s[N],f[26];
    int Write[20],WRI;
    void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
    void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));}
    //void add(LL x,LL y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;}
    //void Add(LL x,LL y){add(x,y); add(y,x);}
    int main()
    {
        //judge();
        n=read(); k=read();
        scanf("%s",s+1);
        for (int i=1;i<=n;i++) b[s[i]-'a']=1;
        for (int i=0;i<26;i++)
            if (b[i])
                f[++t]=(char)(i+'a');
        if (n==k)
        {
            int x=n;
            while (s[x]==f[t]) s[x]=f[1],x--;
            for (int i=1;i<=t;i++)
                if (f[i]==s[x])
                {s[x]=f[i+1];
                break;
            }
            for (int i=1;i<=n;i++) printf("%c",s[i]);
        }
        else if (n<k)
        {
            for (int i=1;i<=n;i++) printf("%c",s[i]);
            for (int i=1;i<=k-n;i++) printf("%c",f[1]);
        }
        else
        {
            int x=k;
            while (s[x]==f[t]) s[x]=f[1],x--;
            for (int i=1;i<=t;i++)
                if (f[i]==s[x])
                {s[x]=f[i+1];
                break;
            }
            for (int i=1;i<=k;i++) printf("%c",s[i]);
        }
        return 0;
    }
    View Code

    D:有两个数组a,b,b的生成规则如下:

    b1 = b2 = b3 = b4 = 0.

    For all 5 ≤ i ≤ n:

    • bi = 0 if ai, ai - 1, ai - 2, ai - 3, ai - 4 > r and bi - 1 = bi - 2 = bi - 3 = bi - 4 = 1
    • bi = 1 if ai, ai - 1, ai - 2, ai - 3, ai - 4 < l and bi - 1 = bi - 2 = bi - 3 = bi - 4 = 0
    • bi = bi - 1 otherwise

    求一组满足条件的l,r

    题解:直接暴力求解即可。。。

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<queue>
    #include<vector>
    #define mp make_pair
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pa;
    const int N=100010;
    //struct E{int to,nxt;}e[N<<1];
    int n,b[N],l,r;
    char a[N];
    int Write[20],WRI;
    void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
    void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));}
    //void add(LL x,LL y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;}
    //void Add(LL x,LL y){add(x,y); add(y,x);}
    int main()
    {
        //judge();
        n=read();
        l=-1000000000; r=1000000000;
        for (int i=1;i<=n;i++) b[i]=read();
        scanf("%s",a+1);
        for (int i=5;i<=n;i++)
            if (a[i]!=a[i-1]&&a[i-1]==a[i-2]&&a[i-2]==a[i-3]&&a[i-3]==a[i-4])
                if (a[i]=='1')
                {
                    for (int j=i-4;j<=i;j++)
                        l=max(l,b[j]+1);
                }
                else
                {
                    for (int j=i-4;j<=i;j++)
                        r=min(r,b[j]-1);
                }
        printf("%d %d",l,r);
        return 0;
    }
    View Code

    E:将数组a划分成若干段,使每段的f值之和最小,其中f值是区间内元素和减去前k/c(下取整)小的数。

    题解:考虑去掉2个数,也就是2c<=段长<3c时,将它拆成两段肯定不会变劣,这应该比较显然吧,然后取c肯定不会劣于c+1,那么我们在DP时只要从i-c和i-1转移过来即可,同时要维护[i-c+1,i]的最小值,我是用单调队列的。

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<queue>
    #include<vector>
    #define mp make_pair
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pa;
    const int N=100010;
    //struct E{int to,nxt;}e[N<<1];
    #define int LL
    int n,a[N],c,q[N],h,t;
    LL s[N],f[N];
    int Write[20],WRI;
    void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);}
    int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
    void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));}
    //void add(LL x,LL y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;}
    //void Add(LL x,LL y){add(x,y); add(y,x);}
    signed main()
    {
        //judge();
        n=read(); c=read();
        for (int i=1;i<=n;i++) a[i]=read(),s[i]=s[i-1]+a[i];
        h=1;
        for (int i=1;i<=n;i++)
        {
            f[i]=f[i-1]+a[i];
            while (h<=t&&q[h]<i-c+1) h++;
            while (h<=t&&a[q[t]]>a[i]) t--;
            q[++t]=i;
            //for (int j=h;j<=t;j++) printf("%d ",q[j]); puts("");
            if (i>=c) f[i]=min(f[i],f[i-c]+s[i]-s[i-c]-a[q[h]]);
        }
        printf("%lld",f[n]);
        return 0;
    }
    View Code

    F:给数组a,有两种操作,1 l r查询[l,r]中每个数出现次数的mex,注意是出现次数,mex是最小未出现的自然数,2 x y将a[x]修改为y。

    题解:带修改莫队可以解决此题。带修改莫队不会的同学可以先去做下BZOJ2120,然后mex+莫队可以参考BZOJ3585。带修改莫队就是加入了第三关键字time,然后按(左端点所在块,右端点所在块,时间)排序,其中时间指的是在第几次修改操作后。注意修改时要记下原来的数,以便还原回去。维护mex可以对权值分块,如果某块中数的个数==R-L+1,那么这块所有数都出现了,否则暴力扫,我有个同学直接暴力维护也过了。。。

    #include<cstdio>
    #include<cmath>
    #include<map>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    const int N=200010;
    struct node{int l,r,id,ans,tim;}q[N];
    struct nodee{int x,y,z;}b[N];
    int n,m,pos[N],L[N],R[N],a[N],qn,f[N],h[N],g[N],l,r,cnt,c[N];
    int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
    bool cmp1(node a,node b){return pos[a.l]<pos[b.l]||pos[a.l]==pos[b.l]&&pos[a.r]<pos[b.r]||pos[a.l]==pos[b.l]&&pos[a.r]==pos[b.r]&&a.tim<b.tim;}
    bool cmp2(node a,node b){return a.id<b.id;}
    void add(int x)
    {
        if (--f[h[a[x]]]==0) g[pos[h[a[x]]]]--;
        h[a[x]]++;
        if (++f[h[a[x]]]==1) g[pos[h[a[x]]]]++;
    }
    void del(int x)
    {
        if (--f[h[a[x]]]==0) g[pos[h[a[x]]]]--;
        h[a[x]]--;
        if (++f[h[a[x]]]==1) g[pos[h[a[x]]]]++;
    }
    void add_time(int k)
    {
        int x=b[k].x,y=b[k].y,z=b[k].z;
        if (x>=l&&x<=r) del(x);
        b[k].z=a[x];
        a[x]=y;
        if (x>=l&&x<=r) add(x);
    }
    void del_time(int k)
    {
        int x=b[k].x,y=b[k].y,z=b[k].z;
        if (x>=l&&x<=r) del(x);
        a[x]=z;
        if (x>=l&&x<=r) add(x);
    }
    int query()
    {
        int i=1;
        for (int i=1;i<=pos[n];i++)
            if (g[i]!=R[i]-L[i]+1) break;
        for (int j=L[i];j<=R[i];j++)
            if (!f[j]) return j;
    }
    int main()
    {
        n=read(); m=read();
        int blo=pow(n,2.0/3);
        for (int i=1;i<=n;i++)
        {
            pos[i]=(i-1)/blo+1;
            if (!L[pos[i]]) L[pos[i]]=i;
            R[pos[i]]=i;
        }
        for (int i=1;i<=n;i++) a[i]=read(),c[++cnt]=a[i];
        int now=0;
        for (int i=1;i<=m;i++)
        {
            int op=read(),l=read(),r=read();
            if (op==1) q[++qn]=(node){l,r,i,0,now};
            else b[++now]=(nodee){l,r,0},c[++cnt]=b[now].y;
        }
        sort(c+1,c+1+cnt);
        cnt=unique(c+1,c+cnt+1)-c-1;
        //for (int i=1;i<=cnt;i++) printf("%d ",c[i]); puts("");
        for (int i=1;i<=n;i++) a[i]=lower_bound(c+1,c+1+cnt,a[i])-c;
        for (int i=1;i<=now;i++) b[i].y=lower_bound(c+1,c+1+cnt,b[i].y)-c;
        //for (int i=1;i<=n;i++) printf("%d ",a[i]); puts("");
        sort(q+1,q+1+qn,cmp1);
        l=1; r=0; now=0;
        for (int i=1;i<=qn;i++)
        {
            while (r<q[i].r) add(++r);
            while (r>q[i].r) del(r--);
            while (l>q[i].l) add(--l);
            while (l<q[i].l) del(l++);
            while (now<q[i].tim) add_time(++now);
            while (now>q[i].tim) del_time(now--);
            q[i].ans=query();
        }
        sort(q+1,q+1+qn,cmp2);
        for (int i=1;i<=qn;i++) printf("%d
    ",q[i].ans);
        return 0;
    }
    View Code
  • 相关阅读:
    nsis打包
    学习记录:ST表
    学习记录:快速幂
    学习记录:哈夫曼树
    学习记录:二叉树
    学习记录:康托展开 与 逆康托展开
    堆排序简介
    动态规划水题集
    lower_bound( ) 与 upper_bound( )
    琐碎的一点技巧
  • 原文地址:https://www.cnblogs.com/lujiaju6555/p/8468709.html
Copyright © 2011-2022 走看看