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\n",sum);
        }
        else printf("%d\n",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\n",f[m&1][n]<INF?f[m&1][n]:-1);
    return 0;
}
posted @ 2017-04-16 23:07  FallDream  阅读(170)  评论(0编辑  收藏  举报