2017 国庆湖南 Day3

Posted 日拱一卒 功不唐捐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017 国庆湖南 Day3相关的知识,希望对你有一定的参考价值。

期望得分:100+30+60=190

实际得分:10+0+55=65

 

到了233 2是奇数位 或223 第2个2是偶数位就会223 、233 循环

#include<cstdio>

#define N 1000001

using namespace std;

char s[N+5];

int main()
{
    freopen("trans.in","r",stdin);
    freopen("trans.out","w",stdout);
    int n,k; bool ok;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        scanf("%s",s+1);
        ok=false;
        for(int i=1;i<n;i++) 
        {
            if(s[i]==\'2\' && s[i+1]==\'3\')
            {
                k--;
                if(s[i-1]==\'2\')
                {
                    if(i&1) s[i+1]=\'2\';
                    else 
                    {
                        for(int j=1;j<i;j++) printf("%c",s[j]);
                        if(k&1) printf("2");
                        else printf("3");
                        for(int j=i+1;j<=n;j++) printf("%c",s[j]);
                        ok=true; break;
                    }
                }
                else if(s[i+2]==\'3\')
                {
                    if(i&1)
                    {
                        for(int j=1;j<=i;j++) printf("%c",s[j]);
                        if(k&1) printf("3");
                        else printf("2");
                        for(int j=i+2;j<=n;j++) printf("%c",s[j]);
                        ok=true; break;
                    }
                    else s[i]=\'3\';
                }
                else
                {
                    if(i&1) s[i+1]=\'2\';
                    else s[i]=\'3\';
                }
                if(!k) break;
            }
        }
        if(!ok) 
            for(int i=1;i<=n;i++) printf("%c",s[i]);
        printf("\\n"); 
    }
    return 0;
}
View Code

 

 

 

注:不能向上走

 

因为蛇可以在一行内任意移动

他最终在一行内的移动范围是一段连续的区间

所以本题可以用区间DP解决

 

f[i][j][k] 表示 前i行,长度为j,从第k列离开第i行的最大得分

g[j][l][r] 表示当前长度为j,在区间[l,r]内移动,没有死亡的最大得分

开始时 ,对于每一个i,f[i][j][k]=g[j][k][k]=f[i-1][g-a[i][k]][k]+max(-a[i][k],0)

然后,区间由内向外更新, g[j][l][r]=max(g[j-a[i][l]][l+1][r]+a[i][l],g[j-a[i][r]][l][r-1]+a[i][r])

最后 更新f f[i][j][k]=max(g[j][l][r]) k∈[l,r]

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

#define N 201

using namespace std;

int a[N][6];

int f[N][N*10][6],g[N*10][6][6];

bool can[N][6];

void read(int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c==\'-\') f=-1; c=getchar(); }
    while(isdigit(c)) { x=x*10+c-\'0\'; c=getchar(); }
    x*=f;
}

int main()
{
    freopen("snakevsblock.in","r",stdin);
    freopen("snakevsblock.out","w",stdout);
    int n,sum=4;
    read(n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=5;j++)
        {
            read(a[i][j]);
            if(a[i][j]>0) sum+=a[i][j]; 
        }
    int m,x,y;
    read(m); 
    for(int i=1;i<=m;i++)
    {
        read(x); read(y);
        can[x][y]=true;
    }
    memset(f,-127,sizeof(f));
    f[0][4][3]=0;
    int r;
    for(int i=1;i<=n;i++)
    {
        memset(g,-127,sizeof(g));
        for(int j=0;j<=sum;j++) 
            for(int k=1;k<=5;k++)
                if(j-a[i][k]>=0) f[i][j][k]=g[j][k][k]=f[i-1][j-a[i][k]][k]+max(-a[i][k],0);
        for(int len=2;len<=5;len++)
            for(int l=1;l+len-1<=5;l++)
                for(int j=0;j<=sum;j++)
                {
                    r=l+len-1;
                    if(!can[i][l] && j-a[i][l]>=0) g[j][l][r]=g[j-a[i][l]][l+1][r]+max(-a[i][l],0);
                    if(!can[i][r-1] && j-a[i][r]>=0) g[j][l][r]=max(g[j][l][r],g[j-a[i][r]][l][r-1]+max(-a[i][r],0));
                    for(int k=l;k<=r;k++) f[i][j][k]=max(f[i][j][k],g[j][l][r]);
                }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=sum;j++)
            for(int k=1;k<=5;k++)
                ans=max(ans,f[i][j][k]);
    printf("%d",ans);        
}
View Code

 

 

 

前 30%: O(2^n * n^3)

暴力枚举哪些站点损坏,floyd判断这些站点损坏时,测试的站点是否连通 

 另20%:O(nlogn+k)

问题转化为选择最少的点覆盖所有的线段

即留下最多的区间,使区间不相交

按右端点从小到大排序 ,删掉与当前区间有交的区间

另10%:分类讨论即可

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 100001

int n,m,k,out=1e6;

int front[N],nxt[N<<1],to[N<<1],tot;

int in[N],ans[N],id[N],cnt;

int cut[N][2];

bool con[16][16],f[16];

int E[N][2];

int vis[N],fa[N][18];

struct node
{
    int l,r,nl,nr;
}e[N*3];

queue<int>q;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-\'0\'; c=getchar(); }
}

void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}

bool cmp(node p,node q)
{
    return p.nr<q.nr;
}

void bfs(int x)
{
    id[x]=++cnt;
    q.push(x);
    int now;
    while(!q.empty())
    {
        now=q.front(); q.pop();
        for(int i=front[now];i;i=nxt[i])
            if(!id[to[i]]) id[to[i]]=++cnt,q.push(to[i]);
    }
}

void solve2(int start)
{
    bfs(start);
    read(k);
    for(int i=1;i<=k;i++) 
    {
        read(e[i].l),read(e[i].r);
        e[i].nl=id[e[i].l];
        e[i].nr=id[e[i].r];
        if(e[i].nl>e[i].nr) swap(e[i].l,e[i].r),swap(e[i].nl,e[i].nr);
    }
    sort(e+1,e+k+1,cmp);
    int sum=0,last=0;
    for(int i=1;i<=k;i++)
        if(e[i].nl>last) last=e[i].nr,ans[++sum]=e[i].r;
    printf("%d\\n",sum);
    for(int i=1;i<=sum;i++) printf("%d ",ans[i]);
}

void judge(int sum)
{
    memset(con,false,sizeof(con));
    for(int i=1;i<=n;i++) if(!f[i]) con[i][i]=true;
    for(int i=1;i<=m;i++) 
        if(!f[E[i][0]] && !f[E[i][1]]) con[E[i][0]][E[i][1]]=con[E[i][1]][E[i][0]]=true;
    for(int h=1;h<=n;h++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(h!=i && h!=j && i!=j && con[i][h] && con[h][j]) con[i][j]=true;
    for(int i=1;i<=k;i++)
        if(con[cut[i][0]][cut[i][1]]) return;
    if(sum<out) 
    {
        out=sum;
        for(int i=1,j=1;i<=n;i++) if(f[i]) ans[j++]=i;
    } 
}

void dfs(int now,int sum)
{
    if(sum>=out) return;
    if(now==n+1)
    {
        judge(sum);
        return;
    }
    dfs(now+1,sum);
    f[now]=true; dfs(now+1,sum+1); f[now]=false;
}

void solve1()
{
    read(k);
    for(int i=1;i<=k;i++) read(cut[i][0]),read(cut[i][1]);
    dfs(1,0);
    printf("%d\\n",out);
    for(int i=1;i<=out;i++) printf("%d ",ans[i]);
}

void dfs2(int x,int y)
{
    id[x]=++tot;
    for(int i=front[x];i;i=nxt[i])    
        if(to[i]!=y) fa[to[i]][0]=x,dfs2(to[i],x);
}

int getlca(int u,int v)
{
    if(u==v) return u;
    if(id[u]<id[v]) swap(u,v);
    for(int i=17;i>=0;i--)
        if(id[fa[u][i]]>id[v]) u=fa[u][i];
    return fa[u][0];
}

void solve3()
{
    tot=0; dfs2(1,0);
    for(int j=1;j<=17;j++)
        for(int i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
    read(k); int u,v,lca;
    for(int i=0;i<k;i++)
    {
        read(u); read(v);
        lca=getlca(u,v);
        vis[u]|=1<<i; 
        for(int j=fa[u][0];j!=lca;j=fa[j][0]) vis[j]|=1<<i;
        vis[v]|=1<<i;
        for(int j=fa[v][0];j!=lca;j=fa[j][0]) 
         vis[j]|=1<<i;
        vis[lca]|=1<<i;
    }
    tot=(1<<k)-1;
    for(int i=1;i<=n;i++)
        if(vis[i]==tot) { printf("1\\n%d",i); return; }
    int s,g;
    int t1,t2,t3;
    if(k==3)
    {
        bool ok=true;;
        for(int i=1;i<=n;i++)
        {
            s=vis[i]; g=0;
            while(s) g+=(s&1),s/=2;
            if(g!=1) { ok=false; break; }
            if(vis[i]==1) t1=i;
            else if(vis[i]==2) t2=i;
            else t3=i;
        }
        if(ok)
        {
            printf("3\\n%d %d %d",t1,t2,t3);
            return;
        }
        else
        {
            int d[8];
            memset(d,0,sizeof(d));
            for(int i=1;i<=n;i++)
            {
                d[vis[i]]=i;
                if(d[tot^vis[i]]) 
                {
                    printf("2\\n%d %d",i,d[tot^vis[i]]);
                    return;
                }
            }
        }
    }
    int r1=0,r2=0,p1;
    for(int i=1;i<=n;i++)
        if(vis[i]!=r1 || vis[i]!=r2)
        {
            if(vis[i]!=r1) r1=vis[i],p1=i;
            else 
            {
                printf("2\\n%d %d",p1,i);
                return;
            }
        }
}

void init()
{
    read(n); read(m);
    int u,v;
    for(int i=1;i<=m;i++)
    {
        read(u); read(v);
        add(u,v);
        in[u]++; in[v]++;
        E[i][0]=u; E[i][1]=v;
    }
    int sum=0,fir;
    for(int i=1;i<=n;i++)  if(in[i]!=2) sum++,fir=i;
    if(sum==2) solve2(fir);
    else if(n<=15) solve1();
    else if(k<=3) solve3();
}

int main()
{
    freopen("ping11.in","r",stdin);
//    freopen("ping.out","w",stdout);
    init();
}
60分暴力

 

满分做法:

将链上的做法搬到树上

对所有的询问,按他们的lca排序

然后从下到上处理树上的节点,若以当前节点为lca的测试站点还连通,就把当前节点破坏

dfs序+树链剖分维护即可

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 100001

int n,m,p;

int cut[N*3][2],lca[N*3];

int siz[N],fa[N][18];

int cnt,id[N],bl[N];

int q[N*3],lr[N][2];

bool f[N<<2];

int ans[N];

int front[N],nxt[N<<1],to[N<<1],tot;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-\'0\'; c=getchar(); }
}

void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}

void init()
{
    read(n); read(m);
    int u,v;
    for(int i=1;i<=m;i++) 
    {
        read(u); read(v);
        add(u,v);
    }
    read(p);
    for(int i=1;i<=p;i++) read(cut[i][0]),read(cut[i][1]);
}

void dfs1(int x,int y)
{
    fa[x][0]=y; siz[x]=1;
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=y) dfs1(to[i],x),siz[x]+=siz[to[i]];
}

void dfs2(int x,int top)
{
    id[x]=++cnt;
    bl[x]=top;
    int y=0;
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=fa[x][0] && siz[to[i]]>siz[y]) y=to[i];
    if(!y) return;
    dfs2(y,top);
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=fa[x][0] && to[i]!=y) dfs2(to[i],to[i]); 
}

void prelca()
{
    for(int i=1;i<=17;i++)
        for(int j=1;j<=n;j++)
            fa[j][i]=fa[fa[j][i-1]][i-1];
}

int getlca(int u,int v)
{
    if(u==v) return u;
    if(id[u]<id[v]) swap(u,v);
    for(int i=17;i>=0;i--)
        if(id[fa[u][i]]>id[v]) u=fa[u][i];
    return fa[u][0];
}

bool cmp(int a,int b)
{
    return lca[a]<lca[b];
}

void modify(int k,int l,int r,int pos)
{
    f[k]=true;
    if(l==r)   return; 
    int mid=l+r>>1;
    if(pos<=mid) modify(k<<1,l,mid,pos);
    else modify(k<<1|1,mid+1,r,pos);
}

bool query(int k,int l,int r,int opl,int opr)
{
    if(l==opl && r==opr) return f[k];
    int mid=l+r>>1;
    if(opr<=mid) return query(k<<1,l,mid,opl,opr);
    if(opl>mid) return query(k<<1|1,mid+1,r,opl,opr);
    return query(k<<1,l,mid,opl,mid)|query(k<<1|1,mid+1,r,mid+1,opr); 
}

bool QUERY(int u,int v)
{
    while(bl[u]!=bl[v])
    {
        if(id[u]<id[v]) swap(u,v);
        if(query(1,1,cnt,id[bl[u]],id[u])) return true;
        u=fa[bl[u]][0];
    }
    return query(1,1,cnt,min(id[v],id[u]),max(id[v],id[u])) ;
}

void work(int x)
{
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=fa[x][0]) work(to[i]);  
    for(int i=lr[x][0];i<=lr[x][1];i++)
        if(!QUERY(cut[q[i]][0],cut[q[i]][1]))
        {
            modify(1,1,cnt,id[x]);
            ans[++ans[0]]=x;
            return;
        }
}

void solve()
{
    for(int i=1;i<=p;i++) lca[i]=getlca(cut[i][0],cut[i][1]),q[i]=i;
    sort(q+1,q+p+1,cmp);
    for(int i=1;i<=n;i++) lr[i][0]=p+1,lr[i][1]=0;
    for(int i=1;i<=p;i++)
    {
        lr[lca[q[i]]][0]=min(lr[lca[q[i]]][0],i);
        lr[lca[q[i]]][1]=max(lr[lca[q[i]]][1],i);
    }
    work(以上是关于2017 国庆湖南 Day3的主要内容,如果未能解决你的问题,请参考以下文章

2017 国庆湖南 Day1

湖南集训day3

17国庆day3

清北学堂国庆day3解题报告

2019牛客国庆集训派对day3 排列(状压dp)

2019牛客国庆集训派对day3 时间旅行(思维)