首页 > 代码库 > Codeforces Round #408(div.2)

Codeforces Round #408(div.2)

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


凌晨打比赛真的难受,十一点趴下去,一觉起来感觉精神非常迷糊  脑子不好使了

------------------------------------------------------------------------------

A. Buying A House

给定n个点,每个点有一个价格。你有一些钱,你要求钱够买的情况下,离一个特殊点的最近距离。

小模拟

#include<cstdio>#include<iostream>#include<cstring>#include<map>#include<queue>#include<algorithm>#include<set>#include<cmath>#define MN 10005#define INF 200000000using namespace std;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,s[MN+5],m,ans=INF,k;int abs(int x){return  x<0?-x:x;}int main(){    n=read();k=read();m=read();    for(int i=1;i<=n;i++)s[i]=read();    for(int i=1;i<=n;i++)if(s[i]&&s[i]<=m)        ans=min(ans,abs(k-i));    printf("%d\n",ans*10);    return 0;}

B. Find The Bone
有n个位置,一个球放在位置1,有m个位置有洞。k个操作,每次交换两个位置的东西,如果球到了洞上面,他就会掉下去,求球的最后位置。

大模拟

#include<cstdio>#include<iostream>#include<cstring>#include<map>#include<queue>#include<algorithm>#include<set>#include<cmath>#define MN 1000005#define INF 200000000using namespace std;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,k,pos=1;bool b[MN+5];int main(){    n=read();m=read();k=read();    for(int i=1;i<=m;i++)b[read()]=1;    if(b[1])return 0*puts("1");    for(int i=1;i<=k;i++)    {        int u=read(),v=read();        if(u==pos)        {            pos=v;if(b[v])return 0*printf("%d\n",v);        }        else if(v==pos)        {            pos=u;if(b[u])return 0*printf("%d\n",u);        }    }    printf("%d\n",pos);    return 0;}

C. Bank Hacking

有一棵n个节点的树,每个节点有一个权值,你要先选择一个节点,然后破坏它,与这个点连通且距离小等于2的点权值+1,然后你不断选择一个已经破坏的点的相邻节点破坏,求破坏的最大权值的最小值  n<=300000

很容易发现是选择一个点不变,与他相邻的+1,其它+2,取一个最大值。所以可以直接暴力枚举,算一下有多少个最大值和 与每个点相邻的最大值有几个  就可以轻松算出答案。

我菜,写了线段树。

#include<cstdio>#include<iostream>#include<cstring>#include<map>#include<queue>#include<algorithm>#include<set>#include<cmath>#define ll long long#define N 524288#define MN 300005#define INF 2000000000using namespace std;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;}struct edge{int to,next;}e[MN*5];int cnt=0,n,a[MN+5],head[MN+5],ans=INF;int T[MN*10];void renew (int x,int ad){    T[x+=N]=ad;    for(x>>=1;x;x>>=1)        T[x]=max(T[x<<1],T[x<<1|1]);}int query(int l,int r){    int sum=-INF;    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)    {        if(~l&1) sum=max(sum,T[l+1]);        if( r&1) sum=max(sum,T[r-1]);    }    return sum;}void ins(int f,int t){    e[++cnt]=(edge){t,head[f]};head[f]=cnt;    e[++cnt]=(edge){f,head[t]};head[t]=cnt;}int main(){    n=read();    memset(T,128,sizeof(T));    for(int i=1;i<=n;i++)        a[i]=read(),renew(i,a[i]+2);    for(int i=1;i<n;i++)    {        int x=read(),y=read();        ins(x,y);    }    for(int x=1;x<=n;x++)    {        renew(x,a[x]);        for(int i=head[x];i;i=e[i].next)            renew(e[i].to,a[e[i].to]+1);        ans=min(ans,query(1,n));        renew(x,a[x]+2);        for(int i=head[x];i;i=e[i].next)            renew(e[i].to,a[e[i].to]+2);    }    printf("%d\n",ans);    return 0;}

D.给定一棵树,一些节点是特殊节点,满足所有点到最近的特殊节点的距离不超过d,你要删去尽可能多的边,并且保证这个条件依旧满足,输出删去的数量和方案。

考虑从每个特殊节点开始bfs,如果一条边到的节点已经被bfs到了,删掉它。注意去重。

#include<cstdio>#include<iostream>#include<cstring>#include<map>#include<queue>#include<algorithm>#include<set>#include<cmath>#define ll long long#define MN 300005#define INF 200000000using 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;}struct edge{int to,next;}e[MN*5];int cnt=1,n,k,mx,head[MN+5],d[MN+5],num,q[MN+5],sum=0,fa[MN+5],ans[MN+5];void ins(int f,int t){    e[++cnt]=(edge){t,head[f]};head[f]=cnt;    e[++cnt]=(edge){f,head[t]};head[t]=cnt;}int main(){    n=read();k=read();mx=read();    memset(d,42,sizeof(d));    for(int i=1;i<=k;i++)    {        int x=read();if(d[x]<INF)continue;        q[++num]=x;d[x]=0;    }    for(int i=1;i<n;i++) ins(read(),read());    for(int i=1;i<=num;i++)        for(int j=head[q[i]];j;j=e[j].next)        if(e[j].to!=fa[q[i]])        {            if(d[e[j].to]<INF) sum+=ans[j>>1]^1,ans[j>>1]=1;            else d[q[++num]=e[j].to]=d[q[i]]+1,fa[e[j].to]=q[i];        }    printf("%d\n",sum);    for(int i=1;i<n;i++)        if(ans[i]) printf("%d ",i);    return 0;}

E 有n道题,你可以偷看p次答案,每次只能看连续的k道题。但是你只能看相邻的两个人,并且这些人不一定都是对的。
给出n,p,k和两个人分别有哪些题使得对的,求最多能看对(#滑稽)几道题  n,p<=1000 k<=50

考虑dp,用f[i][j][x][y]表示前i道题,看了j次,第一个人还能看x道题,第二个人还能看y道题。每次转移i后移一格之后,x,y都会-1(如果它不是0),也就是说看了这一题。当然,你也可以选择让j+1使得x和y变成k-1,也就是从这里开始看,后面的k-1道题当然都能看到啦。(感觉讲的不清不楚)

这样复杂度就是$O(npk^{2})$,不能通过此题,但是我们发现$p\geqslant 2\lceil\frac{n}{k}\rceil$的时候,我一定能看到所有题,只要这两个人有人做对了它。

这样p最大变成2n/k,复杂度降低为$O(n^{2}k)$,足够通过。空间的话,我们把第一维滚动一下呗。

#include<iostream>#include<cstdio>#include<cstring>#define INF 30000using 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,p,k,m;short f[2][1003][53][53];bool s[2][1003];inline void R(short&x,short y){if(y>x)x=y;}int main(){    memset(f,128,sizeof(f));    n=read();p=read();k=read();    m=read();for(int i=1;i<=m;i++) s[0][read()]=1;    m=read();for(int i=1;i<=m;i++) s[1][read()]=1;    if(p>=(n+k-1)/k*2)     {        int ans=0;        for(int i=1;i<=n;i++) ans+=s[0][i]|s[1][i];        return 0*printf("%d\n",ans);    }     f[0][0][0][0]=0;    for(int i=0,now=1,pre=0;i<n;i++,now^=1,pre^=1)    {        for(int j=0;j<=p;j++)            {                         for(int x=0;x<=k;x++)                for(int y=0;y<=k;y++)                {                    if(!x&&!y)                     {                        R(f[now][j][0][0],f[pre][j][0][0]);                        R(f[now][j+1][0][k-1],f[pre][j][0][0]+s[1][i+1]);                        R(f[now][j+1][k-1][0],f[pre][j][0][0]+s[0][i+1]);                        R(f[now][j+2][k-1][k-1],f[pre][j][0][0]+(s[0][i+1]|s[1][i+1]));                     }                     else if(!x)                    {                        R(f[now][j][0][y-1],f[pre][j][0][y]+s[1][i+1]);                        R(f[now][j+1][k-1][y-1],f[pre][j][0][y]+(s[0][i+1]|s[1][i+1]));                        R(f[now][j+2][k-1][k-1],f[pre][j][0][y]+(s[0][i+1]|s[1][i+1]));                    }                    else if(!y)                    {                          R(f[now][j][x-1][0],f[pre][j][x][0]+s[0][i+1]);                          R(f[now][j+1][x-1][k-1],f[pre][j][x][0]+(s[0][i+1]|s[1][i+1]));                          R(f[now][j+2][k-1][k-1],f[pre][j][x][0]+(s[0][i+1]|s[1][i+1]));                    }                        else                         R(f[now][j][x-1][y-1],f[pre][j][x][y]+(s[1][i+1]|s[0][i+1]));                    f[pre][j][x][y]=-INF;                }        }        }        short ans=0;    for(int x=0;x<k;x++)        for(int y=0;y<k;y++)            R(ans,f[n&1][p][x][y]);    printf("%d\n",(int)ans);    return 0;}

 

Codeforces Round #408(div.2)