Educational Codeforces Round 19

A. k-Factorization

题目大意:给一个数n,求k个大于1的数,乘积为n。(n<=100,000,k<=20)

思路:分解质因数呗

#include<cstdio>
#define MN 100000
int a[MN+5],an;
int main()
{
    int n,k,i;
    scanf("%d%d",&n,&k);
    for(i=2;k>1&&n>1;++i)for(;k>1&&n%i==0;--k,n/=i)a[++an]=i;
    if(n==1)return 0*puts("-1");
    for(i=1;i<=an;++i)printf("%d ",a[i]);printf("%d",n);
}

B. Odd sum

题目大意:给你n个数,求和为奇数的子序列的最大和。(n<=10^5)

思路:大于0的偶数直接加入答案,把奇数排序,先选一个最大的把它删掉并加入答案,while剩下的最大的的两个奇数和大于0就加入答案并删掉。

#include<cstdio>
#include<algorithm>
using namespace std;
char B[1<<26],*S=B,C;int X,F;
inline int read()
{
    for(F=1;(C=*S++)<'0'||C>'9';)if(C=='-')F=-1;
    for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=(X<<3)+(X<<1)+C-'0';
    return X*F;
}
#define MN 100000
int a[MN+5],an;
int main()
{
    fread(B,1,1<<26,stdin);
    int n=read(),i,x,ans=0;
    for(i=1;i<=n;++i)
        if((x=read())&1)a[++an]=x;
        else if(x>0)ans+=x;
    sort(a+1,a+an+1);
    ans+=a[an];
    for(i=an;--i>1;--i)if(a[i]+a[i-1]>0)ans+=a[i]+a[i-1];else break;
    printf("%d",ans);
}

C. Minimal string

题目大意:给出一个序列的入栈顺序,求字典序最小的可能的出栈顺序。(序列长度<=10^5)

思路:堆+双向链表贪心,选了一个元素后之后只能选这个元素的前一个元素和后面的元素,每次选能选的最小且位置最前的。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MN 100000
char s[MN+5];
int ls[MN+5],nx[MN+5],u[MN+5];
struct node
{
    char c;int x;
    bool operator<(const node&b)const{return c==b.c?x>b.x:c>b.c;}
};
priority_queue<node> pq;
int main()
{
    int n,i,l,x;
    scanf("%s",s+1);n=strlen(s+1);
    for(i=1;i<=n;++i)ls[i]=i-1,nx[i]=i+1,pq.push((node){s[i],i});
    for(i=l=1;i<=n;++i)
    {
        while((x=pq.top().x)<l||u[x])pq.pop();
        u[x]=1;putchar(pq.top().c);pq.pop();
        if(ls[x]<l&&ls[x])pq.push((node){s[ls[x]],ls[x]});
        l=ls[x];nx[ls[x]]=nx[x];ls[nx[x]]=ls[x];
    }
}

D. Broken BST

题目大意:给出一棵n个节点的树,每一个点有一个权值,对每个点的权值从根节点开始按二叉搜索树的方式查询,问有多少个点的权值不会被查到。(n<=10^5)

思路:dfs求出会走到每个节点的数字区间。

#include<cstdio>
#include<map>
using namespace std;
char B[1<<26],*S=B,C;int X,F;
inline int read()
{
    for(F=1;(C=*S++)<'0'||C>'9';)if(C=='-')F=-1;
    for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=(X<<3)+(X<<1)+C-'0';
    return X*F;
}
#define MN 100000
#define MX 1000000000
int v[MN+5],l[MN+5],r[MN+5],d[MN+5];
map<int,int> mp;
void dfs(int x,int L,int R)
{
    if(x<0)return;
    if(L<=v[x]&&v[x]<=R)mp[v[x]]=1;
    if(L<v[x])dfs(l[x],L,min(R,v[x]-1));
    if(R>v[x])dfs(r[x],max(L,v[x]+1),R);
}
int main()
{
    fread(B,1,1<<26,stdin);
    int n=read(),i,ans=0;
    for(i=1;i<=n;++i)v[i]=read(),
        (l[i]=read())>0?++d[l[i]]:0,
        (r[i]=read())>0?++d[r[i]]:0;
    for(i=1;i<=n;++i)if(!d[i])dfs(i,0,MX);
    for(i=1;i<=n;++i)if(!mp[v[i]])++ans;
    printf("%d",ans);
}

E. Array Queries

题目大意:给出n和ai(1<=i<=n),一次变换定义为把p变成p+a[p]+k,q次询问,每次给出p和k,问要多少次能把p变成大于n的数。(n,q<=10^5)

思路:分块,对于k<=n^0.5直接预处理出各个p和k的答案,对于k>n^0.5答案最大不会超过n^0.5,直接暴力,复杂度O(n^1.5)。

#include<cstdio>
inline int read()
{
    int x;char c;
    while((c=getchar())<'0'||c>'9');
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
    return x;
}
#define MN 100000
#define MK 350
int a[MN+5],f[MK+5][MN+5];
int main()
{
    int n=read(),q,i,k,ans;
    for(i=1;i<=n;++i)a[i]=read();
    for(k=1;k<=MK;++k)for(i=n;i;--i)f[k][i]=i+a[i]+k>n?1:f[k][i+a[i]+k]+1;
    for(q=read();q--;)
    {
        i=read();k=read();
        if(k<=MK)printf("%d
",f[k][i]);
        else{for(ans=0;i<=n;i+=a[i]+k)++ans;printf("%d
",ans);}
    }
}

F. Mice and Holes

题目大意:n只老鼠m个洞分别位于数轴上,每个洞有容量ci,求每个老鼠都进洞的最小距离和。(n,m<=5,000)

思路:把老鼠和洞分别排序,最优方案下进每个洞的老鼠必然是连续的区间,f[i][j]表示前i个洞进前j只老鼠的最小距离和,s[i][j]表示前j只老鼠都进第i个洞的距离和,f[i][j]=min(f[i-1][k]+s[i][j]-s[i][k])(j-k<=ci),单调队列维护即可,复杂度O(nm)。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define MN 5000
struct hole{int p,c;}h[MN+5];
bool cmp(hole a,hole b){return a.p<b.p;}
int x[MN+5],q[MN+5],ql,qr;
ll f[MN+5][MN+5],s[MN+5];
inline int z(int x){return x<0?-x:x;}
int main()
{
    int n,m,i,j;ll cnt=0;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;++i)scanf("%d",&x[i]);
    for(i=1;i<=m;++i)scanf("%d%d",&h[i].p,&h[i].c),cnt+=h[i].c;
    if(cnt<n)return 0*puts("-1");
    sort(x+1,x+n+1);sort(h+1,h+m+1,cmp);
    memset(f,42,sizeof(f));f[0][0]=0;
    for(i=1;i<=m;++i)for(q[ql=1,qr=0]=j=0;j<=n;++j)
    {
        s[j]=s[j-1]+z(h[i].p-x[j]);
        while(ql<=qr&&f[i-1][j]-s[j]<=f[i-1][q[qr]]-s[q[qr]])--qr;q[++qr]=j;
        while(j-q[ql]>h[i].c)++ql;
        f[i][j]=f[i-1][q[ql]]+s[j]-s[q[ql]];
    }
    printf("%I64d",f[m][n]);
}