Bestcoder round#33 解题报告

来源:互联网 发布:个人信用数据库包含 编辑:程序博客网 时间:2024/06/02 00:54

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

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

0 0
原创粉丝点击