Bestcoder round#33 解题报告

1001

简单的进制转换问题。

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

using namespace std;
char p[36];
int a[310];
char s[310];
int n,b,l;
int main()
{
    for (int i=0;i<=9;i++)
        p[i]=(char)(i+'0');
    for (int i=10;i<36;i++)
        p[i]=(char)(i-10+'a');
    while (scanf("%d %d",&n,&b)==2)
    {
        memset(a,0,sizeof(a));
        for (int i=1;i<=n;i++)
        {
            scanf("%s",s);
            l=strlen(s);
            int pos=0;
            for (int j=l-1;j>=0;j--)
            {
                int d;
                if (s[j]>='0'&&s[j]<='9') d=s[j]-'0';
                else d=s[j]-'a'+10;
                a[pos++]+=d;
            }
        }
        int flag=0;
        for (int i=0;i<=220;i++)
        {
            a[i]%=b;
            if (a[i]) flag=i;
        }
        for (int i=flag;i>=0;i--)
            printf("%c",p[a[i]]);
        printf("\n");
    }
    return 0;
}

1002

我们所选取的a[i]一定是整个序列中最大或者最小的,这两种情况完全等价。不妨考虑a[i]是最大数这种情况:选出a[i]后,剩下有n-1个数,对于每个数都有两种放法,放在a[i]左侧或者放在a[i]右侧,一共 2n1 种。如果每个数放左还是放右已经确定了,那么显然整个序列也就确定了。那么总方案数应该为 2n 种。但是会有重复:a[i]最大,且左边没有数,和a[i]最小,且右边没有数;a[i]最大,且右边没有数,和a[i]最小,且左边没有数。所以ans应该为 2n2 。但是我们需要注意特判n=1的情况,此时答案应该为1 。

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

using namespace std;
typedef long long LL;
LL p;
LL n;
LL multi(LL a, LL b)
{
    LL ret=0;
    while(b)
    {
        if(b&1) ret=(ret+a)%p;
        a=(a+a)%p;
        b>>=1;
    }
    return ret;
}
LL pow_mod(LL a,LL b)
{
    LL ret=1;
    while(b)
    {
        if(b&1) ret=multi(ret,a)%p;
        a=multi(a,a)%p;
        b>>=1;
    }
    return ret;
}

int main()
{
    while (cin>>n>>p)
    {
        if (n==1) cout<<1%p<<endl;
        else
        {
            LL ans=pow_mod(2,n)-2;
            while (ans<0) ans+=p;
            cout<<ans<<endl;
        }
    }
    return 0;
}

1003

简单的背包问题,不过注意物品的选取顺序有讲究。我们需要按照l[i]-t[i]的大小,从小到大进行排序(满足拓扑序),之后就跟最简单的01背包完全一致了。

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

using namespace std;
typedef long long LL;
LL f[1100000];
int l[40],v[40],t[40],b[40],a[40];
int cmp(int x,int y)
{
    return b[x]<b[y];
}
int n,w,maxx,tt;
int main()
{
    while (scanf("%d %d",&n,&w)==2)
    {
        memset(f,0,sizeof(f));
        maxx=tt=0;
        for (int i=1;i<=n;i++)
        {
            scanf("%d %d %d",&t[i],&v[i],&l[i]);
            a[i]=i;
            maxx=max(maxx,l[i]);
            tt+=t[i];
            b[i]=l[i]-t[i];
        }
        tt+=maxx;
        sort(a+1,a+1+n,cmp); 
        for (int i=1;i<=n;i++)
        {
            int ll=max(t[a[i]],l[a[i]]);
            for (int j=tt;j>=ll;j--)
            {
                f[j]=max(f[j],f[j-t[a[i]]]+(LL)v[a[i]]);
            }
        }
        int flag=0;
        for (int i=1;i<=tt;i++)
        {
            if (f[i]>=w)
            {
                flag=1;
                printf("%d\n",i);
                break;
            }
        }
        if (!flag) printf("zhx is naive!\n");
    }
    return 0;
}

1004

很容易想到二分,设答案为ans。那么我们需要判断是否存在一组wb,hb,wg,hg,满足 wbhb+wghgwb+wgans ,即

answbwbhb+answgwghg0

显然此时我们是要维护斜率,由于询问是在树上的一个简单路径。所以我们需要将树树链剖分,然后在每个线段树上建凸包,在凸包内二分。思路很简单,但是由于太弱,还没调试成功,为了打卡,先把题解放在这里,等以后过了,再把代码贴上来。

你可能感兴趣的:(Bestcoder round#33 解题报告)