2016"百度之星" - 初赛(Astar Round2A)解题报告

1001

感觉离散课上都讲过。。k很小,,由于 ai=ai110+xmodk 。所以在这样的完全由数字x构成的序列,必然在前k+1次进入循环。我们只要暴力找出这个循环就行了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>

using namespace std;

typedef long long LL;
int cas;
LL x,m,k,c;
int way[11000];
int pp[11000];
int tail,ini;
int main()
{
    int T;
    cin>>T;
    while (T--)
    {
        cin>>x>>m>>k>>c;
        printf("Case #%d:\n",++cas);
        memset(pp,-1,sizeof(pp));
        tail=0;
        LL now=0;
        for (int i=0;;i++)
        {
            now=now*10+x;
            now%=k;
            if (pp[now]==-1)
            {
                pp[now]=i;
                way[tail++]=now;
            }
            else
            {
                ini=pp[now];
                break;
            }
        }
        int begin=ini;
        m--;
        if (m<=ini)
        {
            if (way[m]==c) printf("Yes\n");
            else printf("No\n");
        }
        else
        {
            m-=ini;
            m%=(tail-ini);
            if (way[m+ini]==c) printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}

1002

n<16,所以我们可以状压dp搞一波,f[i][j]表示数字枚举状态为i,最后一个数为j,所能获得的最大分数。注意一些细节即可。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>

using namespace std;

typedef long long LL;
const int maxn=1<<17;
int cas;
int n;
LL f[maxn][16];
LL way[16],a[16];
int pp[16];
int p[16];
int main()
{
    int T;
    cin>>T;
    while (T--)
    {
        printf("Case #%d:\n",++cas);
        memset(way,-1,sizeof(way));
        memset(pp,0,sizeof(pp));
        cin>>n;
        for (int i=0;i<n;i++)
        {
            cin>>a[i]>>p[i];
            if (p[i]!=-1) pp[i]=1,way[p[i]]=i;
        }
        for (int i=1;i<(1<<n);i++)
            for (int j=0;j<n;j++)
                f[i][j]=-2e9;
        if (way[0]!=-1)
        {
            f[1<<way[0]][way[0]]=0;
        }
        else
        {
            for (int i=0;i<n;i++)
                if (!pp[i]) f[1<<i][i]=0;
        }
        for (int i=1;i<(1<<n);i++)
        {
            int l=0,x=i;
            while (x) l+=x%2,x/=2;
            l--;
            if (way[l]!=-1)
            {
                for (int j=0;j<n;j++)
                {                   
                    if (j==way[l]||!(i&(1<<j))||(way[l-1]!=-1&&way[l-1]!=j)) continue;
                    f[i][way[l]]=max(f[i][way[l]],f[i^(1<<way[l])][j]+a[j]*a[way[l]]);
                }

                continue;
            }
            for (int j=0;j<n;j++)
            {
                if (f[i][j]!=-2e9||!(i&(1<<j))||(way[l]!=-1&&way[l]!=j)) continue;
                for (int k=0;k<n;k++)
                {
                    if (j==k||!(i&(1<<k))||(way[l-1]!=-1&&way[l-1]!=k)) continue;
                        f[i][j]=max(f[i][j],f[i^(1<<j)][k]+a[k]*a[j]);
                }
            }
        }
        LL ans=-2e9;
        for (int i=0;i<n;i++)
            ans=max(ans,f[(1<<n)-1][i]);
        cout<<ans<<endl;

    }
    return 0;
}

1003

利用树的dfs序来维护每个节点到0的权值。每个子树都可以用dfs序中连续的一段表示。而此题,将一个零食机权值改变后,相当于将以这个点为根节点的子树所有权值减去/加上一个数。查询也是相当于查询以必经点为根节点的子树的权值的最大值。显然我们用一棵线段树维护即可。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>

using namespace std;

typedef __int64 LL;

struct data{
   int l,r;
   LL max,lazy;
}tr[4000001];
LL a[400050];
int pos;
int in[410000],out[410000];
int e[410000],pre[410000],last[410000];
LL val[410000];
int pp[410000];
int n,m;
int cas;
void build(int k,int s,int t)
{
    tr[k].l=s;tr[k].r=t;
    tr[k].lazy=0;
    if(s==t)
    {
        tr[k].max=val[s];       
        return;
    }
    int mid=(s+t)>>1;
    build(k<<1,s,mid);
    build(k<<1|1,mid+1,t);
    tr[k].max=max(tr[k<<1].max,tr[k<<1|1].max);
}
void pushdown(int k)
{
    tr[k<<1].max+=tr[k].lazy;
    tr[k<<1|1].max+=tr[k].lazy;
    tr[k<<1].lazy+=tr[k].lazy;
    tr[k<<1|1].lazy+=tr[k].lazy;
    tr[k].lazy=0;
}
void change(int k,int a,int b,LL c)
{
    int l=tr[k].l,r=tr[k].r;
    if(a==l&&b==r)
    {
        tr[k].max+=(LL)c;
        tr[k].lazy+=(LL)c;
        return;
    } 
    if(tr[k].lazy!=0) pushdown(k);
    int mid=(l+r)>>1;
    if(b<=mid) change(k<<1,a,b,c);
    else if(a>mid) change(k<<1|1,a,b,c);
    else change(k<<1,a,mid,c),change(k<<1|1,mid+1,b,c);
    tr[k].max=max(tr[k<<1].max,tr[k<<1|1].max);
}
LL query(int k,int a,int b)
{
    int l=tr[k].l,r=tr[k].r;
    if (a==l&&b==r)
    {
        return tr[k].max;
    }
    if(tr[k].lazy!=0) pushdown(k);
    int mid=(l+r)>>1;
    LL res=-1e15; 
    if(b<=mid) res=max(res,query(k<<1,a,b));
    else if(a>mid) res=query(k<<1|1,a,b);
    else res=max(query(k<<1,a,mid),query(k<<1|1,mid+1,b));
    tr[k].max=max(tr[k<<1].max,tr[k<<1|1].max);
    return res;

}
void dfs(int x,LL now)
{
    now+=a[x];
    val[++pos]=now;
    pp[x]=1;
    in[x]=pos;
    for (int i=last[x];i!=0;i=pre[i])
    {
        if (!pp[e[i]]) dfs(e[i],now);
    }
    out[x]=pos;
}
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        printf("Case #%d:\n",++cas);
        pos=0;
        int num=0;
        memset(pp,0,sizeof(pp));
        memset(last,0,sizeof(last));
        scanf("%d %d",&n,&m);
        for (int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            x++,y++;
            e[++num]=y;
            pre[num]=last[x];
            last[x]=num;
            e[++num]=x;
            pre[num]=last[y];
            last[y]=num;
        }
        for (int i=1;i<=n;i++)
            scanf("%I64d",&a[i]);
        dfs(1,0);
        build(1,1,n);
        for (int i=1;i<=m;i++)
        {
            int op,x;
            LL y;
            scanf("%d",&op);
            if (op==0)
            {
                scanf("%d %I64d",&x,&y);
                x++;
                change(1,in[x],out[x],y-a[x]);
                a[x]=y;
            }
            else
            {
                scanf("%d",&x);
                x++;
                printf("%I64d\n",query(1,in[x],out[x]));
            }
        }
    }
    return 0;
}

1004

动态规划。关键思路在于,我们只用考虑长度为2或者为3的等差数列。然后进行区间dp即可。f[i][j]表示i到j这段中最多删去多少个数字,那么首先继承f[i+1][j]和f[i][j-1]中较大的那个,然后考虑将[i,j]划分成两个区间[i,l],[l+1,j]。再考虑如果i,j两点构成等差,且区间[i+1,j-1]可以全部删去。再考虑i和一中间点l构成等差,l和j构成等差,i,l,j三点构成等差的情况即可。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>

using namespace std;

typedef long long LL;
map<int,int> S;
int g[400][400];
int a[400];
int f[400][400];
int n,m;
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        memset(g,0,sizeof(g));
        memset(f,0,sizeof(f));
        scanf("%d %d",&n,&m);
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for (int i=1;i<=m;i++)
        {
            int x;
            scanf("%d",&x);
            for (int i=1;i<=n;i++)
            {
                for (int j=i+1;j<=n;j++)
                    if (a[j]-a[i]==x) g[i][j]=1;
            }
        }
        for (int k=2;k<=n;k++)
        {
            for (int i=1,j=k;j<=n;i++,j++)
            {
                for (int l=i;l<j;l++)
                    f[i][j]=max(f[i][j],f[i][l]+f[l+1][j]);
                if (g[i][j] && f[i+1][j-1]==(j-1)-(i+1)+1)
                    f[i][j]=j-i+1;
                for (int l=i+1;l<j;l++)
                {
                    if (g[i][l] && f[i+1][l-1]==(l-1)-(i+1)+1) f[i][j]=max(f[i][j],2+f[i+1][l-1]+f[l+1][j]);
                    if (g[l][j] && f[l+1][j-1]==(j-1)-(l+1)+1) f[i][j]=max(f[i][j],2+f[l+1][j-1]+f[i][l-1]);
                    if (g[i][l] && g[l][j]&&a[j]-a[l]==a[l]-a[i]&&f[i+1][l-1]==(l-1)-(i+1)+1&&f[l+1][j-1]==(j-1)-(l+1)+1)
                        f[i][j]=j-i+1;
                }
            }
        }
        printf("%d\n",f[1][n]);
    }
    return 0;
}

1005

递归处理即可。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>

using namespace std;

typedef long long LL;
int cas;
LL x,m,k,c;
int way[11000];
int pp[11000];
int tail,ini;
int main()
{
    int T;
    cin>>T;
    while (T--)
    {
        cin>>x>>m>>k>>c;
        printf("Case #%d:\n",++cas);
        memset(pp,-1,sizeof(pp));
        tail=0;
        LL now=0;
        for (int i=0;;i++)
        {
            now=now*10+x;
            now%=k;
            if (pp[now]==-1)
            {
                pp[now]=i;
                way[tail++]=now;
            }
            else
            {
                ini=pp[now];
                break;
            }
        }
        int begin=ini;
        m--;
        if (m<=ini)
        {
            if (way[m]==c) printf("Yes\n");
            else printf("No\n");
        }
        else
        {
            m-=ini;
            m%=(tail-ini);
            if (way[m+ini]==c) printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}

1006

从小到大bfs,判断至少多少人在其后面。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>

using namespace std;

typedef long long LL;
int pp[110000],e[110000],pre[110000],last[110000];
LL ans;
LL now;
int n,m;
void bfs(int x)
{
    now++;
    pp[x]=1;
    for (int i=last[x];i!=0;i=pre[i])
    {
        if (!pp[e[i]]) bfs(e[i]);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d %d",&n,&m);
        memset(pp,0,sizeof(pp));
        memset(last,0,sizeof(last));
        for (int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            e[i]=y;
            pre[i]=last[x];
            last[x]=i;
        }    
        ans=0;
        for (int i=1;i<=n;i++)
        {
            if (!pp[i])
            {
                now=0;
                bfs(i);
                ans+=now*i;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

你可能感兴趣的:(2016"百度之星" - 初赛(Astar Round2A)解题报告)