zoukankan      html  css  js  c++  java
  • Educational Codeforces Round#19

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


    A. k-Factorization

    给出n和k,问n能不能分成k个大于1的数字的乘积,输出方案。n<=100000 k<=20

    直接分解质因数,k大于质因数数量时候无解,其他时候随便搞成k个输出就行了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<set>
    #include<map>
    #define INF 2000000000
    #define ll long long
    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 n,num,s[12313],k;
    
    int main()
    {
        n=read();k=read();
        for(int i=2;n>1;i++)
            while(n%i==0) n/=i,s[++num]=i;
        if(num<k)return 0*puts("-1");
        for(int i=k+1;i<=num;i++) s[k]*=s[i];
        for(int i=1;i<=k;i++) cout<<s[i]<<" ";
        return 0;
    }

    B. Odd sum

    给定n个数,你要选出一个子序列,满足和是奇数且最大。n<=10^5

    对于偶数显然把大于0的全选即可,奇数特判一下各种情况,如果大于0的数量是偶数,不选最小的;不然如果没有大于0的,选一个最大的。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<set>
    #include<map>
    #define INF 2000000000
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return f?x:-x;
    }
    
    int n,s[100005],ans=0,mn=INF,mx=-INF,num=0;
    bool flag=false;
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)s[i]=read();
        for(int i=1;i<=n;i++)
        {
            if(s[i]>0)
            {
                if(!(s[i]&1)) ans+=s[i];
                else flag=true,ans+=s[i],num++,mn=min(mn,s[i]);
            }
            else if(s[i]&1) mx=max(mx,s[i]);
        }
        if(!flag) ans+=mx;
        else if(!(num&1)) ans+=max(mx,-mn);
        cout<<ans;
        return 0;
    }

    C.Minimal string

    你有一个字符串s,你每次可以选择一种操作1

    1)把s最前面的那个字符入栈 2)输出栈顶的字符,弹掉它。  你要让输出的字符串字典序最小。  |s|<=10^5

    题解:拿一个堆,把所有字符都塞进去,另外维护一个栈顶的位置。每次先把堆里面在栈顶左边的全部弹掉,然后找出堆里面最小的中最靠前的,和栈顶对比,如果它比栈顶小,那么选择它,他们之间的字符全部入栈,否则就出栈。这样一定能找到最小的字符串。实现的话 再上一个双向链表吧 复杂度nlogn

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<set>
    #include<map>
    #define INF 2000000000
    #define MN 100000
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return f?x:-x;
    }
    
    char st[MN+5];
    struct node
    {
        int x,pos;
        bool operator<(const node&b)const{return x==b.x?pos>b.pos:x>b.x;}
    };
    priority_queue<node> q;
    int pos,ne[MN+5],la[MN+5],now;
    bool mark[MN+5];
    
    void del(int x)
    {
        mark[x]=1;
        la[ne[x]]=la[x];
        ne[la[x]]=ne[x];
    }
    
    int main()
    {
        scanf("%s",st+1);
        for(int i=1;st[i];++i) q.push((node){st[i]-'a',i});
        for(int i=1;st[i];i++) ne[i]=i+1,la[i]=i-1;
        while(!q.empty())
        {
            while(!q.empty()&&q.top().pos<pos) q.pop();
            if(q.empty()) break;
            int x=q.top().x;
            if(now&&x>=st[now]-'a') printf("%c",st[now]),del(now),now=la[now];
            else
            {
                pos=q.top().pos;printf("%c",q.top().x+'a');
                del(pos);now=la[pos];q.pop();
            }
        }
        for(;pos;pos--) if(!mark[pos])printf("%c",st[pos]);
        return 0;
    }

    D.Broken BST

    你有一个数组,并且把它建成了一棵假的二叉搜索树,然后你把每个数组里面的数字都查一遍,问有多少个数字查不到。n<=100000

    直接模拟线段树查数值,并且把能查到的数值全部用map记下来,最后每个数字去map里面找一下就行了。复杂度nlogn

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<set>
    #include<map>
    #define INF 2000000000
    #define MN 100000
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return f?x:-x;
    }
    
    int n,L[MN+5],R[MN+5],s[MN+5],in[MN+5],ans=0;
    map<int,bool> mp;
    
    void dfs(int x,int l,int r)
    {
        if(s[x]>=l&&s[x]<=r) mp[s[x]]=1;
        if(L[x]!=-1) dfs(L[x],l,min(s[x]-1,r));
        if(R[x]!=-1) dfs(R[x],max(l,s[x]+1),r);
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
        {
            s[i]=read();L[i]=read();R[i]=read();
            if(L[i]!=-1) in[L[i]]++;
            if(R[i]!=-1) in[R[i]]++;
        }
        for(int i=1;i<=n;i++)
            if(!in[i]) dfs(i,0,INF);
        for(int i=1;i<=n;i++) if(!mp[s[i]]) ans++;
        cout<<ans;
        return 0;
    }

    E. Array Queries

    给定n个数ai,m个询问,每次给出p,k,然后每当p小等于n的时候,p就变成p+ap+k,问这个变化的次数  n,m<=100000  1<=ai,p,k<=n

    对于k<=$sqrt{n}$的询问,我们预处理答案,k更大的,显然次数不会超过根号次,暴力跳. 复杂度$O(n^{frac{3}{2}})$

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<set>
    #include<map>
    #define INF 2000000000
    #define MN 100000
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') f = 0;ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return f?x:-x;
    }
    int num[350][MN+5],n,mx,m,s[MN+5];
    int main()
    {
        n=read();mx=sqrt(n);
        for(int i=1;i<=n;i++)s[i]=read();m=read();
        for(int i=0;i<=mx;i++)
            for(int j=n;j;--j) num[i][j]=num[i][min(n+1,j+s[j]+i)]+1;
        for(int i=1;i<=m;i++)
        {
            int x=read(),k=read();
            if(k>mx)
            {
                int sum=0;
                for(;x!=n+1;x=min(n+1,x+s[x]+k)) ++sum;
                printf("%d
    ",sum);
            }
            else printf("%d
    ",num[k][x]);
        }
        return 0;
    }

    F. Mice and Holes

    有n只老鼠,m个洞,老鼠和洞在一个数轴上,且都有一个坐标,每个洞有最大容量ci。第i只老师进到第j个洞的费用是他们之间的距离,求最小费用。n,m<=5000

    用f[i][j]表示前i只老鼠进到前j个洞的最小费用,s[i][j]表示前i只老鼠都到第j个洞的总费用

    那么f[i][j]=min(f[k][j-1]+s[i][j]-s[k][j]),i-k<=cj

    发现这个式子中s[i][j]是不变的,所以我们开一个单调队列维护就行了。复杂度O(nm)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define pa pair<ll,int>
    #define mp(x,y) make_pair(x,y)
    #define ll long long
    #define MN 5000
    #define INF 200000000000000000LL
    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,x[MN+5];
    ll f[2][MN+5],s[MN+5][MN+5];
    struct hole
    {    
        int x,c;
        bool operator<(const hole&b)const{return x<b.x;}
    }y[MN+5];
    struct MyQueue
    {
        int top,tail;pa q[MN+5];
        void clear(){q[top=tail=0]=mp(0,0);}
        void push(ll x,int pos)
        {
            while(top>=tail&&x<=q[top].first) --top;
            q[++top]=mp(x,pos);
        }
        ll get(int pos)
        {
            while(top>=tail&&q[tail].second<pos) ++tail;
            if(top<tail) return INF;
            return q[tail].first;
        }
    }q;
    
    inline int abs(int x){return x<0?-x:x;}
    
    int main()
    {
        memset(f,127,sizeof(f));
        n=read();m=read();
        for(int i=1;i<=n;i++) x[i]=read();
        for(int i=1;i<=m;i++) y[i].x=read(),y[i].c=read();
        sort(x+1,x+n+1);sort(y+1,y+m+1);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                s[i][j]=s[i-1][j]+abs(x[i]-y[j].x);
        f[0][0]=0;
        for(int j=1,now=1,pre=0;j<=m;j++)
        {
            q.clear();
            for(int i=1;i<=n;i++)
            {
                f[now][i]=q.get(i-y[j].c)+s[i][j];
                q.push(f[pre][i]-s[i][j],i);
                f[now][i]=min(f[now][i],f[pre][i]);
            }
            now^=1;pre^=1;memset(f[now],127,sizeof(f[now]));
        }
        printf("%lld
    ",f[m&1][n]<INF?f[m&1][n]:-1);
        return 0;
    }
  • 相关阅读:
    FJoi2017 1月21日模拟赛 comparison(平衡树+thita重构)
    juruo的刷题&博文祭
    [bzoj4247][挂饰] (动规+排序)
    FJoi2017 1月20日模拟赛 直线斯坦纳树(暴力+最小生成树+骗分+人工构造+随机乱搞)
    FJoi2017 1月20日模拟赛 交错和(等差数列+rmq)
    FJoi2017 1月20日模拟赛 恐狼后卫(口糊动规)
    【spoj 5971】lcmsum
    【bzoj 4025 改编版】graph
    【CF 718C】fibonacci
    【CF 482E】ELCA
  • 原文地址:https://www.cnblogs.com/FallDream/p/codeforcesedu19.html
Copyright © 2011-2022 走看看